diff --git a/redisinsight/ui/src/pages/browser/modules/key-details-header/KeyDetailsHeader.tsx b/redisinsight/ui/src/pages/browser/modules/key-details-header/KeyDetailsHeader.tsx index fd9fdc170c..072e0d50ee 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details-header/KeyDetailsHeader.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details-header/KeyDetailsHeader.tsx @@ -72,7 +72,7 @@ const KeyDetailsHeader = ({ const dispatch = useDispatch() const handleRefreshKey = () => { - dispatch(refreshKey(keyBuffer!, type)) + dispatch(refreshKey(keyBuffer!, type, undefined, length)) } const handleEditTTL = (key: RedisResponseBuffer, ttl: number) => { diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/RejsonDetailsWrapper.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/RejsonDetailsWrapper.tsx index e1f94976ee..948283a452 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/RejsonDetailsWrapper.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/RejsonDetailsWrapper.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import { useSelector } from 'react-redux' import { EuiProgress } from '@elastic/eui' @@ -22,12 +22,16 @@ const RejsonDetailsWrapper = (props: Props) => { const keyType = KeyTypes.ReJSON const { loading } = useSelector(rejsonSelector) const { data, downloaded, type, path } = useSelector(rejsonDataSelector) - const { name: selectedKey } = useSelector(selectedKeyDataSelector) || {} + const { name: selectedKey, nameString, length } = useSelector(selectedKeyDataSelector) || {} const { id: instanceId } = useSelector(connectedInstanceSelector) const { viewType } = useSelector(keysSelector) const [expandedRows, setExpandedRows] = useState>(new Set()) + useEffect(() => { + setExpandedRows(new Set()) + }, [nameString]) + const reportJSONKeyCollapsed = (level: number) => { sendEventTelemetry({ event: getBasedOnViewTypeEvent( @@ -56,7 +60,7 @@ const RejsonDetailsWrapper = (props: Props) => { }) } - const reportJsonKeyExpandAndCollapse = (isExpanded: boolean, path: string) => { + const handleJsonKeyExpandAndCollapse = (isExpanded: boolean, path: string) => { const matchedPath = path.match(/\[.+?\]/g) const levelFromPath = matchedPath ? matchedPath.length - 1 : 0 if (isExpanded) { @@ -100,9 +104,10 @@ const RejsonDetailsWrapper = (props: Props) => { selectedKey={selectedKey || stringToBuffer('')} dataType={type || ''} data={data as IJSONData} + length={length} parentPath={path} expadedRows={expandedRows} - onJsonKeyExpandAndCollapse={reportJsonKeyExpandAndCollapse} + onJsonKeyExpandAndCollapse={handleJsonKeyExpandAndCollapse} isDownloaded={downloaded} /> )} diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/components/edit-entire-item-action/EditEntireItemAction.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/components/edit-entire-item-action/EditEntireItemAction.tsx index 0e6458329e..f229d7e581 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/components/edit-entire-item-action/EditEntireItemAction.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/components/edit-entire-item-action/EditEntireItemAction.tsx @@ -55,7 +55,7 @@ const EditEntireItemAction = (props: Props) => {
onCancel?.()}> -
+
handleOnEsc(e)} /> { const { data, selectedKey, + length, dataType, parentPath, isDownloaded, @@ -35,11 +36,11 @@ const RejsonDetails = (props: BaseProps) => { dispatch(fetchVisualisationResults(path, forceRetrieve)) const handleAppendRejsonArrayItemAction = (keyName: RedisResponseBuffer, path: string, data: string) => { - dispatch(appendReJSONArrayItemAction(keyName, path, data)) + dispatch(appendReJSONArrayItemAction(keyName, path, data, length)) } const handleSetRejsonDataAction = (keyName: RedisResponseBuffer, path: string, data: string) => { - dispatch(setReJSONDataAction(keyName, path, data)) + dispatch(setReJSONDataAction(keyName, path, data, length)) } const handleFormSubmit = ({ key, value }: { key?: string, value: string }) => { @@ -56,7 +57,7 @@ const RejsonDetails = (props: BaseProps) => { } const onClickRemoveKey = (path: string, keyName: string) => { - dispatch(removeReJSONKeyAction(selectedKey, path || '.', keyName)) + dispatch(removeReJSONKeyAction(selectedKey, path || '.', keyName, length)) } const onClickSetRootKVPair = () => { diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-object/RejsonObject.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-object/RejsonObject.tsx index dbc1e19977..668744e411 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-object/RejsonObject.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-object/RejsonObject.tsx @@ -40,20 +40,22 @@ const RejsonObject = (props: JSONObjectProps) => { const [valueOfEntireObject, setValueOfEntireObject] = useState('') const [addNewKeyValuePair, setAddNewKeyValuePair] = useState(false) const [loading, setLoading] = useState(false) - const [isExpanded, setIsExpanded] = useState(expadedRows?.has(path) || false) + const [isExpanded, setIsExpanded] = useState(false) useEffect(() => { - if (!isExpanded) { + if (!expadedRows?.has(path)) { setValue(defaultValue) return } if (isDownloaded) { setValue(currentValue) - } else { - fetchObject() + setIsExpanded(expadedRows?.has(path)) + return } - }, [isExpanded, isDownloaded]) + + fetchObject() + }, []) const handleFormSubmit = ({ key, value }: { key?: string, value: string }) => { setAddNewKeyValuePair(false) @@ -82,8 +84,23 @@ const RejsonObject = (props: JSONObjectProps) => { } const onClickExpandCollapse = (path: string) => { - onJsonKeyExpandAndCollapse(!isExpanded, path) - setIsExpanded((v) => !v) + if (isExpanded) { + onJsonKeyExpandAndCollapse(false, path) + setIsExpanded(false) + setValue(defaultValue) + + return + } + + if (isDownloaded) { + onJsonKeyExpandAndCollapse(true, path) + setIsExpanded(true) + setValue(currentValue) + + return + } + + fetchObject() } const fetchObject = async () => { @@ -96,6 +113,7 @@ const RejsonObject = (props: JSONObjectProps) => { setDownloaded(downloaded) clearTimeout(spinnerDelay) setLoading(false) + setIsExpanded(true) } catch { clearTimeout(spinnerDelay) setIsExpanded(false) @@ -188,4 +206,4 @@ const RejsonObject = (props: JSONObjectProps) => { ) } -export default RejsonObject +export default React.memo(RejsonObject) diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-scalar/RejsonScalar.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-scalar/RejsonScalar.tsx index b66b275132..f653d9722b 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-scalar/RejsonScalar.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/rejson-scalar/RejsonScalar.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react' import { useDispatch } from 'react-redux' import cx from 'classnames' -import { isString } from 'lodash' +import { isNull, isString } from 'lodash' import { setReJSONDataAction } from 'uiSrc/slices/browser/rejson' import InlineItemEditor from 'uiSrc/components/inline-item-editor/InlineItemEditor' import PopoverDelete from 'uiSrc/pages/browser/components/popover-delete/PopoverDelete' @@ -35,7 +35,7 @@ const RejsonScalar = (props: JSONScalarProps) => { const dispatch = useDispatch() useEffect(() => { - setChangedValue(isString(value) ? `"${value}"` : value) + setChangedValue(isString(value) ? `"${value}"` : isNull(value) ? 'null' : value) }, [value]) const onDeclineChanges = () => { diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/styles.module.scss b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/styles.module.scss index 16865adc46..c90e02b8ec 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/styles.module.scss +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/rejson-details/styles.module.scss @@ -79,6 +79,7 @@ .controlsBottom { background-color: var(--euiColorLightestShade); height: 24px !important; + margin-bottom: 4px !important; z-index: 2; display: flex; align-items: center; diff --git a/redisinsight/ui/src/slices/browser/keys.ts b/redisinsight/ui/src/slices/browser/keys.ts index cfd6a9c9ec..f508c946d1 100644 --- a/redisinsight/ui/src/slices/browser/keys.ts +++ b/redisinsight/ui/src/slices/browser/keys.ts @@ -683,7 +683,7 @@ export function fetchKeyInfo(key: RedisResponseBuffer, resetData?: boolean) { dispatch(fetchSetMembers(key, 0, SCAN_COUNT_DEFAULT, '*', resetData)) } if (data.type === KeyTypes.ReJSON) { - dispatch(fetchReJSON(key, '.', resetData)) + dispatch(fetchReJSON(key, '.', data.length, resetData)) } if (data.type === KeyTypes.Stream) { const { viewType } = state.browser.stream @@ -1255,7 +1255,12 @@ export function editKeyTTLFromList(data: [RedisResponseBuffer, number]) { } } -export function refreshKey(key: RedisResponseBuffer, type: KeyTypes | ModulesKeyTypes, args?: IFetchKeyArgs) { +export function refreshKey( + key: RedisResponseBuffer, + type: KeyTypes | ModulesKeyTypes, + args?: IFetchKeyArgs, + length?: number +) { return async (dispatch: AppDispatch) => { const resetData = false dispatch(refreshKeyInfoAction(key)) @@ -1281,7 +1286,7 @@ export function refreshKey(key: RedisResponseBuffer, type: KeyTypes | ModulesKey break } case KeyTypes.ReJSON: { - dispatch(fetchReJSON(key, '.', true)) + dispatch(fetchReJSON(key, '.', length, true)) break } case KeyTypes.Stream: { diff --git a/redisinsight/ui/src/slices/browser/rejson.ts b/redisinsight/ui/src/slices/browser/rejson.ts index 409a6187f8..4f5567dc43 100644 --- a/redisinsight/ui/src/slices/browser/rejson.ts +++ b/redisinsight/ui/src/slices/browser/rejson.ts @@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import axios, { AxiosError, CancelTokenSource } from 'axios' import * as jsonpath from 'jsonpath' +import { isNumber } from 'lodash' import { ApiEndpoints } from 'uiSrc/constants' import { apiService } from 'uiSrc/services' import { getBasedOnViewTypeEvent, sendEventTelemetry, TelemetryEvent, getJsonPathLevel } from 'uiSrc/telemetry' @@ -24,6 +25,8 @@ import { InitialStateRejson, RedisResponseBuffer } from '../interfaces' import { addErrorNotification, addMessageNotification } from '../app/notifications' import { AppDispatch, RootState } from '../store' +const JSON_LENGTH_TO_FORCE_RETRIEVE = 200 + export const initialState: InitialStateRejson = { loading: false, error: null, @@ -123,7 +126,12 @@ export default rejsonSlice.reducer export let sourceRejson: Nullable = null // Asynchronous thunk action -export function fetchReJSON(key: RedisResponseBuffer, path = '.', resetData?: boolean) { +export function fetchReJSON( + key: RedisResponseBuffer, + path = '.', + length?: number, + resetData?: boolean, +) { return async (dispatch: AppDispatch, stateInit: () => RootState) => { dispatch(loadRejsonBranch(resetData)) @@ -143,7 +151,7 @@ export function fetchReJSON(key: RedisResponseBuffer, path = '.', resetData?: bo { keyName: key, path, - forceRetrieve: false, + forceRetrieve: isNumber(length) && length > JSON_LENGTH_TO_FORCE_RETRIEVE, encoding, }, { cancelToken: sourceRejson.token } @@ -168,6 +176,7 @@ export function setReJSONDataAction( key: RedisResponseBuffer, path: string, data: string, + length?: number, onSuccessAction?: () => void, onFailAction?: () => void ) { @@ -207,7 +216,7 @@ export function setReJSONDataAction( } dispatch(setReJSONDataSuccess()) - dispatch(fetchReJSON(key, '.')) + dispatch(fetchReJSON(key, '.', length)) dispatch(refreshKeyInfoAction(key)) onSuccessAction?.() } @@ -224,7 +233,8 @@ export function setReJSONDataAction( export function appendReJSONArrayItemAction( key: RedisResponseBuffer, path: string, - data: string + data: string, + length?: number ) { return async (dispatch: AppDispatch, stateInit: () => RootState) => { dispatch(appendReJSONArrayItem()) @@ -257,7 +267,7 @@ export function appendReJSONArrayItemAction( } }) dispatch(appendReJSONArrayItemSuccess()) - dispatch(fetchReJSON(key, '.')) + dispatch(fetchReJSON(key, '.', length)) dispatch(refreshKeyInfoAction(key)) } } catch (error) { @@ -272,7 +282,8 @@ export function appendReJSONArrayItemAction( export function removeReJSONKeyAction( key: RedisResponseBuffer, path = '.', - jsonKeyName = '' + jsonKeyName = '', + length?: number ) { return async (dispatch: AppDispatch, stateInit: () => RootState) => { dispatch(removeRejsonKey()) @@ -305,7 +316,7 @@ export function removeReJSONKeyAction( } }) dispatch(removeRejsonKeySuccess()) - dispatch(fetchReJSON(key, '.')) + dispatch(fetchReJSON(key, '.', length)) dispatch(refreshKeyInfoAction(key)) dispatch( addMessageNotification(