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 @@ -20,7 +20,7 @@ export const DisplayHeader = ({
const { setSelectedListItem } = useDatabrowserStore()

const handleAddItem = () => {
setSelectedListItem({ key: type === "stream" ? "*" : "", value: "", isNew: true })
setSelectedListItem({ key: type === "stream" ? "*" : "", isNew: true })
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useEffect } from "react"
import type { SelectedItem } from "@/store"
import { useDatabrowserStore } from "@/store"
import type { ListDataType } from "@/types"
Expand All @@ -7,6 +8,7 @@ import { Button } from "@/components/ui/button"
import { Spinner } from "@/components/ui/spinner"
import { SimpleTooltip } from "@/components/ui/tooltip"

import { useFetchListItems } from "../../hooks"
import { useEditListItem } from "../../hooks/use-edit-list-item"
import { headerLabels } from "./display-list"
import { useField } from "./input/use-field"
Expand All @@ -30,19 +32,41 @@ export const ListEditDisplay = ({
const ListEditForm = ({
type,
dataKey,
item: { key: itemKey, value: itemValue, isNew },
item: { key: itemKey, isNew },
}: {
type: ListDataType
dataKey: string
item: SelectedItem
}) => {
const query = useFetchListItems({
type,
dataKey,
})
// Search in pages for item value
const findValue = () => {
for (const page of query.data?.pages ?? []) {
const item = page.keys.find((item) => item.key === itemKey)
// Check if item has a value property before returning it
if (item && "value" in item) return item.value as string
}
return
}
const itemValue = findValue()

const form = useForm({
defaultValues: {
key: itemKey,
value: itemValue,
},
})

useEffect(() => {
form.reset({
key: itemKey,
value: itemValue,
})
}, [itemKey, itemValue])

const { mutateAsync: editItem, isPending } = useEditListItem()
const { setSelectedListItem } = useDatabrowserStore()

Expand Down Expand Up @@ -70,6 +94,7 @@ const ListEditForm = ({
name="key"
height={type === "set" ? 250 : 100}
label={keyLabel}
data={itemKey}
/>
)}

Expand All @@ -82,6 +107,7 @@ const ListEditForm = ({
name="value"
height={type === "list" ? 250 : 100}
label={valueLabel}
data={itemValue ?? ""}
/>
)
)}
Expand Down Expand Up @@ -142,12 +168,14 @@ const FormItem = ({
label,
height,
readOnly,
data,
}: {
name: string
label: string
isNumber?: boolean
height?: number
readOnly?: boolean
data: string
}) => {
const form = useFormContext()
const { editor, selector } = useField({
Expand All @@ -156,6 +184,7 @@ const FormItem = ({
height: height,
showCopyButton: true,
readOnly,
data,
})

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const ListItems = ({
data-item-key={key}
data-item-value={value}
onClick={() => {
setSelectedListItem({ key, value })
setSelectedListItem({ key })
}}
className="h-10 border-b border-b-zinc-100 hover:bg-zinc-50"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,21 @@ const EditorDisplayForm = ({
const form = useForm({
defaultValues: { value: data },
})
const { editor, selector } = useField({ name: "value", form })

const { mutateAsync: setKey, isPending: isSettingKey } = useSetSimpleKey(dataKey, type)

// Updates default values after submit
useEffect(() => {
form.reset(
{ value: data },
{
keepValues: true,
keepValues: false,
}
)
}, [data])

const { editor, selector } = useField({ name: "value", form, data })

const { mutateAsync: setKey, isPending: isSettingKey } = useSetSimpleKey(dataKey, type)

const handleCancel = () => {
form.reset()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ export const useField = ({
height,
showCopyButton,
readOnly,
data,
}: {
name: string
form: UseFormReturn<any>
height?: number
showCopyButton?: boolean
readOnly?: boolean
data: string
}) => {
const { field, fieldState } = useController<Record<string, string>>({
name,
Expand All @@ -26,16 +28,16 @@ export const useField = ({
checkIsValidJSON(field.value) ? "JSON" : "Text"
)

// Attempt to format JSON on initial load
// Attempt to format JSON everytime the underlying data changes
useEffect(() => {
if (!checkIsValidJSON(field.value)) {
if (!checkIsValidJSON(data)) {
return
}

form.setValue(name, formatJSON(field.value), {
form.setValue(name, formatJSON(data), {
shouldDirty: false,
})
}, [])
}, [data])

const handleTypeChange = (type: ContentType) => {
setContentType(type)
Expand Down
5 changes: 4 additions & 1 deletion src/components/databrowser/components/sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { queryClient } from "@/lib/clients"
import { Button } from "@/components/ui/button"
import { Spinner } from "@/components/ui/spinner"

import { FETCH_LIST_ITEMS_QUERY_KEY } from "../../hooks"
import { FETCH_LIST_ITEMS_QUERY_KEY, FETCH_SIMPLE_KEY_QUERY_KEY } from "../../hooks"
import { useKeys } from "../../hooks/use-keys"
import { AddKeyModal } from "../add-key-modal"
import { DisplayDbSize, FETCH_DB_SIZE_QUERY_KEY } from "./db-size"
Expand Down Expand Up @@ -32,6 +32,9 @@ export function Sidebar() {
queryClient.invalidateQueries({
queryKey: [FETCH_LIST_ITEMS_QUERY_KEY],
})
queryClient.invalidateQueries({
queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY],
})
queryClient.invalidateQueries({
queryKey: [FETCH_DB_SIZE_QUERY_KEY],
})
Expand Down
17 changes: 17 additions & 0 deletions src/components/databrowser/hooks/use-fetch-simple-key.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,26 @@ export const useFetchSimpleKey = (dataKey: string, type: DataType) => {
else if (type === "json") result = (await redis.json.get(dataKey)) as string | null
else throw new Error(`Invalid type when fetching simple key: ${type}`)

if (type === "json" && result !== null)
result = JSON.stringify(sortObject(JSON.parse(result)))

if (result === null) deleteKeyCache(dataKey)

return result
},
})
}

// Add recursive key sorting to a JSON object
const sortObject = (obj: unknown): unknown => {
if (typeof obj !== "object" || obj === null) return obj
return Object.fromEntries(
Object.entries(obj)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([key, value]) =>
typeof value === "object" && !Array.isArray(value) && value !== null
? [key, sortObject(value)]
: [key, value]
)
)
}
3 changes: 1 addition & 2 deletions src/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export type SearchFilter = {

export type SelectedItem = {
key: string
value?: string
isNew?: boolean
}

Expand All @@ -68,7 +67,7 @@ type DatabrowserStore = {
setSelectedKey: (key: string | undefined) => void

selectedListItem?: SelectedItem
setSelectedListItem: (item?: { key: string; value?: string; isNew?: boolean }) => void
setSelectedListItem: (item?: { key: string; isNew?: boolean }) => void

search: SearchFilter
setSearch: (search: SearchFilter) => void
Expand Down