diff --git a/redisinsight/ui/src/config/default.ts b/redisinsight/ui/src/config/default.ts
index efacc5591b..70b3c9305f 100644
--- a/redisinsight/ui/src/config/default.ts
+++ b/redisinsight/ui/src/config/default.ts
@@ -84,6 +84,10 @@ export const defaultConfig = {
'RI_DATABASE_OVERVIEW_MINIMUM_REFRESH_INTERVAL',
1,
),
+ rejsonMonacoEditorMaxThreshold: intEnv(
+ 'RI_REJSON_MONACO_EDITOR_MAX_THRESHOLD',
+ 10_000,
+ ),
},
features: {
envDependent: {
diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.spec.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.spec.tsx
index ae97c1de04..cf34b98d66 100644
--- a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.spec.tsx
+++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.spec.tsx
@@ -1,12 +1,16 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import ChangeEditorTypeButton, { ButtonMode } from './ChangeEditorTypeButton'
+
+import ChangeEditorTypeButton from './ChangeEditorTypeButton'
const mockSwitchEditorType = jest.fn()
+let mockIsTextEditorDisabled = false
+
jest.mock('./useChangeEditorType', () => ({
useChangeEditorType: () => ({
switchEditorType: mockSwitchEditorType,
+ isTextEditorDisabled: mockIsTextEditorDisabled,
}),
}))
@@ -16,32 +20,38 @@ describe('ChangeEditorTypeButton', () => {
})
it('should render an enabled button with default tooltip', async () => {
+ mockIsTextEditorDisabled = false
+
render()
const button = screen.getByRole('button', { name: /change editor type/i })
expect(button).toBeEnabled()
await userEvent.hover(button)
-
expect(
await screen.findByText('Edit value in text editor'),
).toBeInTheDocument()
})
- it('should render a disabled button with read-only tooltip', async () => {
- render()
+ it('should render a disabled button with a tooltip', async () => {
+ mockIsTextEditorDisabled = true
+
+ render()
const button = screen.getByRole('button', { name: /change editor type/i })
expect(button).toBeDisabled()
await userEvent.hover(button)
-
expect(
- await screen.findByText('This JSON is too large to edit'),
+ await screen.findByText(
+ 'This JSON document is too large to view or edit in full.',
+ ),
).toBeInTheDocument()
})
it('should call switchEditorType on click when not disabled', async () => {
+ mockIsTextEditorDisabled = false
+
render()
const button = screen.getByRole('button', { name: /change editor type/i })
@@ -51,7 +61,9 @@ describe('ChangeEditorTypeButton', () => {
})
it('should not call switchEditorType when disabled', async () => {
- render()
+ mockIsTextEditorDisabled = true
+
+ render()
const button = screen.getByRole('button', { name: /change editor type/i })
await userEvent.click(button)
diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.tsx
index 6243117d94..f1ed5317b9 100644
--- a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.tsx
+++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/ChangeEditorTypeButton.tsx
@@ -2,24 +2,12 @@ import React from 'react'
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'
import { useChangeEditorType } from './useChangeEditorType'
-export enum ButtonMode {
- editable = 'editable',
- readOnly = 'readOnly',
-}
-
-export type ChangeEditorTypeButtonProps = {
- mode?: ButtonMode
-}
-
-const ChangeEditorTypeButton = ({
- mode = ButtonMode.editable,
-}: ChangeEditorTypeButtonProps) => {
- const { switchEditorType } = useChangeEditorType()
- const isReadMode = mode === ButtonMode.readOnly
+const ChangeEditorTypeButton = () => {
+ const { switchEditorType, isTextEditorDisabled } = useChangeEditorType()
- const isDisabled = isReadMode
- const tooltip = isReadMode
- ? 'This JSON is too large to edit'
+ const isDisabled = isTextEditorDisabled
+ const tooltip = isTextEditorDisabled
+ ? 'This JSON document is too large to view or edit in full.'
: 'Edit value in text editor'
return (
diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/index.ts b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/index.ts
index 1f50dcadb4..a3834f345f 100644
--- a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/index.ts
+++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/index.ts
@@ -1,5 +1,4 @@
import ChangeEditorTypeButton from './ChangeEditorTypeButton'
-export { ButtonMode as ChangeEditorTypeButtonMode } from './ChangeEditorTypeButton'
export { useChangeEditorType } from './useChangeEditorType'
export default ChangeEditorTypeButton
diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.spec.ts b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.spec.ts
index 77a05620d7..2200e59b8b 100644
--- a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.spec.ts
+++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.spec.ts
@@ -1,6 +1,8 @@
import * as reactRedux from 'react-redux'
import { renderHook, act } from '@testing-library/react-hooks'
import { EditorType } from 'uiSrc/slices/interfaces'
+import { FeatureFlags } from 'uiSrc/constants'
+
import { useChangeEditorType } from './useChangeEditorType'
jest.mock('react-redux', () => ({
@@ -56,4 +58,62 @@ describe('useChangeEditorType', () => {
payload: EditorType.Default,
})
})
+
+ describe('isTextEditorDisabled', () => {
+ it('should be false when isWithinThreshold is true', () => {
+ mockedUseSelector
+ .mockImplementationOnce(() => ({
+ editorType: EditorType.Default,
+ isWithinThreshold: true,
+ }))
+ .mockImplementationOnce(() => ({
+ [FeatureFlags.envDependent]: { flag: false },
+ }))
+
+ const { result } = renderHook(() => useChangeEditorType())
+ expect(result.current.isTextEditorDisabled).toBe(false)
+ })
+
+ it('should be false when not within threshold but feature flag is true', () => {
+ mockedUseSelector
+ .mockImplementationOnce(() => ({
+ editorType: EditorType.Default,
+ isWithinThreshold: false,
+ }))
+ .mockImplementationOnce(() => ({
+ [FeatureFlags.envDependent]: { flag: true },
+ }))
+
+ const { result } = renderHook(() => useChangeEditorType())
+ expect(result.current.isTextEditorDisabled).toBe(false)
+ })
+
+ it('should be true when not within threshold and feature flag is false', () => {
+ mockedUseSelector
+ .mockImplementationOnce(() => ({
+ editorType: EditorType.Default,
+ isWithinThreshold: false,
+ }))
+ .mockImplementationOnce(() => ({
+ [FeatureFlags.envDependent]: { flag: false },
+ }))
+
+ const { result } = renderHook(() => useChangeEditorType())
+ expect(result.current.isTextEditorDisabled).toBe(true)
+ })
+
+ it('should be true when envDependentFeature is undefined', () => {
+ mockedUseSelector
+ .mockImplementationOnce(() => ({
+ editorType: EditorType.Default,
+ isWithinThreshold: false,
+ }))
+ .mockImplementationOnce(() => ({
+ [FeatureFlags.envDependent]: undefined,
+ }))
+
+ const { result } = renderHook(() => useChangeEditorType())
+ expect(result.current.isTextEditorDisabled).toBe(true)
+ })
+ })
})
diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.tsx
index 1c77b1dca4..893b13ce30 100644
--- a/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.tsx
+++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/change-editor-type-button/useChangeEditorType.tsx
@@ -1,11 +1,18 @@
import { useCallback } from 'react'
import { useSelector, useDispatch } from 'react-redux'
+import { FeatureFlags } from 'uiSrc/constants'
+import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'
import { rejsonSelector, setEditorType } from 'uiSrc/slices/browser/rejson'
import { EditorType } from 'uiSrc/slices/interfaces'
export const useChangeEditorType = () => {
const dispatch = useDispatch()
- const { editorType } = useSelector(rejsonSelector)
+ const { editorType, isWithinThreshold } = useSelector(rejsonSelector)
+ const { [FeatureFlags.envDependent]: envDependentFeature } = useSelector(
+ appFeatureFlagsFeaturesSelector,
+ )
+
+ const isTextEditorDisabled = !isWithinThreshold && !envDependentFeature?.flag
const switchEditorType = useCallback(() => {
const opposite =
@@ -13,5 +20,5 @@ export const useChangeEditorType = () => {
dispatch(setEditorType(opposite))
}, [dispatch, editorType])
- return { switchEditorType, editorType }
+ return { switchEditorType, editorType, isTextEditorDisabled }
}
diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/monaco-editor/MonacoEditor.spec.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/monaco-editor/MonacoEditor.spec.tsx
index e6fe514993..479f2042a0 100644
--- a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/monaco-editor/MonacoEditor.spec.tsx
+++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/monaco-editor/MonacoEditor.spec.tsx
@@ -10,6 +10,11 @@ const mockStore = configureStore({
browser: {
rejson: {},
},
+ app: {
+ features: {
+ featureFlags: { features: { envDependent: { flag: true } } },
+ },
+ },
}),
})
diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-details/RejsonDetails.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-details/RejsonDetails.tsx
index 7a60ec4107..148e404795 100644
--- a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-details/RejsonDetails.tsx
+++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-details/RejsonDetails.tsx
@@ -1,5 +1,5 @@
import React, { useState } from 'react'
-import { useDispatch, useSelector } from 'react-redux'
+import { useDispatch } from 'react-redux'
import { EuiButtonIcon } from '@elastic/eui'
import cx from 'classnames'
import {
@@ -9,16 +9,12 @@ import {
setReJSONDataAction,
} from 'uiSrc/slices/browser/rejson'
import { RedisResponseBuffer } from 'uiSrc/slices/interfaces'
-import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'
-import { FeatureFlags } from 'uiSrc/constants'
import { getBrackets, isRealArray, isRealObject, wrapPath } from '../utils'
import { BaseProps, ObjectTypes } from '../interfaces'
import RejsonDynamicTypes from '../rejson-dynamic-types'
import { AddItem } from '../components'
-import ChangeEditorTypeButton, {
- ChangeEditorTypeButtonMode,
-} from '../../change-editor-type-button'
+import ChangeEditorTypeButton from '../../change-editor-type-button'
import styles from '../styles.module.scss'
@@ -36,10 +32,6 @@ const RejsonDetails = (props: BaseProps) => {
const [addRootKVPair, setAddRootKVPair] = useState(false)
- const { [FeatureFlags.envDependent]: envDependentFeature } = useSelector(
- appFeatureFlagsFeaturesSelector,
- )
-
const dispatch = useDispatch()
const handleFetchVisualisationResults = (
@@ -104,13 +96,7 @@ const RejsonDetails = (props: BaseProps) => {
'start',
)}
-
+
)}
(fetchReJSON(key, '$', data.length, resetData))
dispatch(setEditorType(EditorType.Default))
+ dispatch(
+ setIsWithinThreshold(
+ data.size <= riConfig.browser.rejsonMonacoEditorMaxThreshold,
+ ),
+ )
}
if (data.type === KeyTypes.Stream) {
const { viewType } = state.browser.stream
diff --git a/redisinsight/ui/src/slices/browser/rejson.ts b/redisinsight/ui/src/slices/browser/rejson.ts
index e9b648883a..ef7e49ddb3 100644
--- a/redisinsight/ui/src/slices/browser/rejson.ts
+++ b/redisinsight/ui/src/slices/browser/rejson.ts
@@ -48,6 +48,7 @@ export const initialState: InitialStateRejson = {
type: '',
},
editorType: EditorType.Default,
+ isWithinThreshold: false,
}
// A slice for recipes
@@ -114,6 +115,9 @@ const rejsonSlice = createSlice({
setEditorType: (state, { payload }: PayloadAction) => {
state.editorType = payload
},
+ setIsWithinThreshold: (state, { payload }: PayloadAction) => {
+ state.isWithinThreshold = payload
+ },
},
})
@@ -132,6 +136,7 @@ export const {
removeRejsonKeySuccess,
removeRejsonKeyFailure,
setEditorType,
+ setIsWithinThreshold,
} = rejsonSlice.actions
// A selector
diff --git a/redisinsight/ui/src/slices/interfaces/instances.ts b/redisinsight/ui/src/slices/interfaces/instances.ts
index 4d6dd7f8c8..9d90aaa0de 100644
--- a/redisinsight/ui/src/slices/interfaces/instances.ts
+++ b/redisinsight/ui/src/slices/interfaces/instances.ts
@@ -497,6 +497,7 @@ export interface InitialStateRejson {
error: Nullable
data: GetRejsonRlResponse
editorType: EditorType
+ isWithinThreshold: boolean
}
export interface ICredentialsRedisCluster {
diff --git a/redisinsight/ui/src/slices/tests/browser/keys.spec.ts b/redisinsight/ui/src/slices/tests/browser/keys.spec.ts
index 6a5bf392eb..075b67cb7a 100644
--- a/redisinsight/ui/src/slices/tests/browser/keys.spec.ts
+++ b/redisinsight/ui/src/slices/tests/browser/keys.spec.ts
@@ -1,9 +1,9 @@
import { cloneDeep } from 'lodash'
import { AxiosError } from 'axios'
import { configureStore } from '@reduxjs/toolkit'
+import { getConfig } from 'uiSrc/config'
import {
BrowserColumns,
- DEFAULT_SHOWN_COLUMNS,
KeyTypes,
KeyValueFormat,
ModulesKeyTypes,
@@ -19,7 +19,6 @@ import {
clearStoreActions,
initialStateDefault,
mockedStore,
- mockStore,
} from 'uiSrc/utils/test-utils'
import {
addErrorNotification,
@@ -33,7 +32,10 @@ import {
} from 'uiSrc/slices/app/context'
import { MOCK_TIMESTAMP } from 'uiSrc/mocks/data/dateNow'
import { rootReducer } from 'uiSrc/slices/store'
-import { setEditorType } from 'uiSrc/slices/browser/rejson'
+import {
+ setEditorType,
+ setIsWithinThreshold,
+} from 'uiSrc/slices/browser/rejson'
import { EditorType } from 'uiSrc/slices/interfaces'
import { CreateHashWithExpireDto } from 'apiSrc/modules/browser/hash/dto'
import {
@@ -109,6 +111,9 @@ import reducer, {
refreshKey,
} from '../../browser/keys'
+const riConfig = getConfig()
+const REJSON_THRESHOLD = riConfig.browser.rejsonMonacoEditorMaxThreshold
+
jest.mock('uiSrc/services', () => ({
...jest.requireActual('uiSrc/services'),
}))
@@ -1400,6 +1405,54 @@ describe('keys slice', () => {
]),
)
})
+
+ it('should set isWithinThreshold to true when length is within threshold', async () => {
+ // Arrange
+ const data = {
+ name: stringToBuffer('rejson'),
+ type: KeyTypes.ReJSON,
+ ttl: -1,
+ size: REJSON_THRESHOLD,
+ length: REJSON_THRESHOLD + 100, // just to make sure this isn't used instead of size
+ }
+ const responsePayload = { data, status: 200 }
+
+ apiService.post = jest.fn().mockResolvedValue(responsePayload)
+
+ // Act
+ await store.dispatch(fetchKeyInfo(data.name))
+
+ // Assert
+ expect(store.getActions()).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining(setIsWithinThreshold(true)),
+ ]),
+ )
+ })
+
+ it('should set isWithinThreshold to false when length exceeds threshold', async () => {
+ // Arrange
+ const data = {
+ name: stringToBuffer('rejson'),
+ type: KeyTypes.ReJSON,
+ ttl: -1,
+ size: REJSON_THRESHOLD + 1,
+ length: REJSON_THRESHOLD, // just to make sure this isn't used instead of size
+ }
+ const responsePayload = { data, status: 200 }
+
+ apiService.post = jest.fn().mockResolvedValue(responsePayload)
+
+ // Act
+ await store.dispatch(fetchKeyInfo(data.name))
+
+ // Assert
+ expect(store.getActions()).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining(setIsWithinThreshold(false)),
+ ]),
+ )
+ })
})
describe('refreshKeyInfoAction', () => {