Skip to content

Commit

Permalink
feat(query-devtools): Add bulk edit option for simple objects and arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
ardeora committed Sep 25, 2024
1 parent be44da3 commit 30007f9
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 17 deletions.
163 changes: 148 additions & 15 deletions packages/query-devtools/src/Devtools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,8 @@ const QueryDetails = () => {
const queryClient = useQueryDevtoolsContext().client

const [restoringLoading, setRestoringLoading] = createSignal(false)
const [dataMode, setDataMode] = createSignal<'view' | 'edit'>('view')
const [dataEditError, setDataEditError] = createSignal<boolean>(false)

Check warning on line 1704 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L1703-L1704

Added lines #L1703 - L1704 were not covered by tests

const errorTypes = createMemo(() => {
return useQueryDevtoolsContext().errorTypes || []
Expand Down Expand Up @@ -2047,22 +2049,85 @@ const QueryDetails = () => {
</Show>
</div>
<div class={cx(styles().detailsHeader, 'tsqd-query-details-header')}>
Data Explorer
</div>
<div
style={{
padding: tokens.size[2],
}}
class="tsqd-query-details-explorer-container tsqd-query-details-data-explorer"
>
<Explorer
label="Data"
defaultExpanded={['Data']}
value={activeQueryStateData()}
editable={true}
activeQuery={activeQuery()}
/>
Data {dataMode() === 'view' ? 'Explorer' : 'Editor'}

Check warning on line 2052 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2052

Added line #L2052 was not covered by tests
</div>
<Show when={dataMode() === 'view'}>
<div
style={{
padding: tokens.size[2],
}}
class="tsqd-query-details-explorer-container tsqd-query-details-data-explorer"
>
<Explorer
label="Data"
defaultExpanded={['Data']}
value={activeQueryStateData()}
editable={true}
onEdit={() => setDataMode('edit')}

Check warning on line 2066 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2066

Added line #L2066 was not covered by tests
activeQuery={activeQuery()}
/>
</div>
</Show>
<Show when={dataMode() === 'edit'}>
<form
class={cx(
styles().devtoolsEditForm,
'tsqd-query-details-data-editor',
)}
onSubmit={(e) => {
e.preventDefault()
const formData = new FormData(e.currentTarget)
const data = formData.get('data') as string
try {
const parsedData = JSON.parse(data)
activeQuery()!.setState({

Check warning on line 2083 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2077-L2083

Added lines #L2077 - L2083 were not covered by tests
...activeQuery()!.state,
data: parsedData,
})
setDataMode('view')

Check warning on line 2087 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2087

Added line #L2087 was not covered by tests
} catch (error) {
setDataEditError(true)

Check warning on line 2089 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2089

Added line #L2089 was not covered by tests
}
}}
>
<textarea
name="data"
class={styles().devtoolsEditTextarea}
onFocus={() => setDataEditError(false)}

Check warning on line 2096 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2096

Added line #L2096 was not covered by tests
data-error={dataEditError()}
value={JSON.stringify(activeQueryStateData(), null, 2)}
></textarea>
<div class={styles().devtoolsEditFormActions}>
<span class={styles().devtoolsEditFormError}>
{dataEditError() ? 'Invalid Value' : ''}

Check warning on line 2102 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2102

Added line #L2102 was not covered by tests
</span>
<div class={styles().devtoolsEditFormActionContainer}>
<button
class={cx(
styles().devtoolsEditFormAction,
css`
color: ${t(colors.gray[600], colors.gray[300])};
`,
)}
type="button"
onClick={() => setDataMode('view')}

Check warning on line 2113 in packages/query-devtools/src/Devtools.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Devtools.tsx#L2113

Added line #L2113 was not covered by tests
>
Cancel
</button>
<button
class={cx(
styles().devtoolsEditFormAction,
css`
color: ${t(colors.blue[600], colors.blue[400])};
`,
)}
>
Save
</button>
</div>
</div>
</form>
</Show>
<div class={cx(styles().detailsHeader, 'tsqd-query-details-header')}>
Query Explorer
</div>
Expand Down Expand Up @@ -3318,6 +3383,74 @@ const stylesFactory = (
}
}
`,
devtoolsEditForm: css`
padding: ${size[2]};
& > [data-error='true'] {
outline: 2px solid ${t(colors.red[200], colors.red[800])};
outline-offset: 2px;
border-radius: ${border.radius.xs};
}
`,
devtoolsEditTextarea: css`
width: 100%;
max-height: 500px;
font-family: 'Fira Code', monospace;
font-size: ${font.size.xs};
border-radius: ${border.radius.sm};
field-sizing: content;
padding: ${size[2]};
background-color: ${t(colors.gray[100], colors.darkGray[800])};
color: ${t(colors.gray[900], colors.gray[100])};
border: 1px solid ${t(colors.gray[200], colors.gray[700])};
resize: none;
&:focus {
outline-offset: 2px;
border-radius: ${border.radius.xs};
outline: 2px solid ${t(colors.blue[200], colors.blue[800])};
}
`,
devtoolsEditFormActions: css`
display: flex;
justify-content: space-between;
gap: ${size[2]};
align-items: center;
padding-top: ${size[1]};
font-size: ${font.size.xs};
`,
devtoolsEditFormError: css`
color: ${t(colors.red[700], colors.red[500])};
`,
devtoolsEditFormActionContainer: css`
display: flex;
gap: ${size[2]};
`,
devtoolsEditFormAction: css`
font-family: ui-sans-serif, Inter, system-ui, sans-serif, sans-serif;
font-size: ${font.size.xs};
padding: ${size[1]} ${tokens.size[2]};
display: flex;
border-radius: ${border.radius.sm};
background-color: ${t(colors.gray[100], colors.darkGray[600])};
border: 1px solid ${t(colors.gray[300], colors.darkGray[400])};
align-items: center;
gap: ${size[2]};
font-weight: ${font.weight.medium};
line-height: ${font.lineHeight.xs};
cursor: pointer;
&:focus-visible {
outline-offset: 2px;
border-radius: ${border.radius.xs};
outline: 2px solid ${colors.blue[800]};
}
&:hover {
background-color: ${t(colors.gray[200], colors.darkGray[500])};
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
`,
}
}

Expand Down
26 changes: 24 additions & 2 deletions packages/query-devtools/src/Explorer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { stringify } from 'superjson'
import { serialize, stringify } from 'superjson'
import { clsx as cx } from 'clsx'
import { Index, Match, Show, Switch, createMemo, createSignal } from 'solid-js'
import { Key } from '@solid-primitives/keyed'
Expand All @@ -9,7 +9,15 @@ import {
displayValue,
updateNestedDataByPath,
} from './utils'
import { Check, CopiedCopier, Copier, ErrorCopier, List, Trash } from './icons'
import {
Check,
CopiedCopier,
Copier,
ErrorCopier,
List,
Pencil,
Trash,
} from './icons'
import { useQueryDevtoolsContext, useTheme } from './contexts'
import type { Query } from '@tanstack/query-core'

Expand Down Expand Up @@ -243,6 +251,7 @@ type ExplorerProps = {
dataPath?: Array<string>
activeQuery?: Query
itemsDeletable?: boolean
onEdit?: () => void
}

function isIterable(x: any): x is Iterable<unknown> {
Expand Down Expand Up @@ -351,6 +360,19 @@ export default function Explorer(props: ExplorerProps) {
dataPath={currentDataPath}
/>
</Show>

<Show when={!!props.onEdit && !serialize(props.value).meta}>

Check warning on line 364 in packages/query-devtools/src/Explorer.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Explorer.tsx#L364

Added line #L364 was not covered by tests
<button
class={styles().actionButton}
title={'Bulk Edit Data'}
aria-label={'Bulk Edit Data'}
onClick={() => {
props.onEdit?.()

Check warning on line 370 in packages/query-devtools/src/Explorer.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/Explorer.tsx#L369-L370

Added lines #L369 - L370 were not covered by tests
}}
>
<Pencil />
</button>
</Show>
</div>
</Show>
</div>
Expand Down
20 changes: 20 additions & 0 deletions packages/query-devtools/src/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,26 @@ export function Copier() {
)
}

export function Pencil() {
return (

Check warning on line 313 in packages/query-devtools/src/icons/index.tsx

View check run for this annotation

Codecov / codecov/patch

packages/query-devtools/src/icons/index.tsx#L312-L313

Added lines #L312 - L313 were not covered by tests
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.5 21.4998L8.04927 19.3655C8.40421 19.229 8.58168 19.1607 8.74772 19.0716C8.8952 18.9924 9.0358 18.901 9.16804 18.7984C9.31692 18.6829 9.45137 18.5484 9.72028 18.2795L21 6.99982C22.1046 5.89525 22.1046 4.10438 21 2.99981C19.8955 1.89525 18.1046 1.89524 17 2.99981L5.72028 14.2795C5.45138 14.5484 5.31692 14.6829 5.20139 14.8318C5.09877 14.964 5.0074 15.1046 4.92823 15.2521C4.83911 15.4181 4.77085 15.5956 4.63433 15.9506L2.5 21.4998ZM2.5 21.4998L4.55812 16.1488C4.7054 15.7659 4.77903 15.5744 4.90534 15.4867C5.01572 15.4101 5.1523 15.3811 5.2843 15.4063C5.43533 15.4351 5.58038 15.5802 5.87048 15.8703L8.12957 18.1294C8.41967 18.4195 8.56472 18.5645 8.59356 18.7155C8.61877 18.8475 8.58979 18.9841 8.51314 19.0945C8.42545 19.2208 8.23399 19.2944 7.85107 19.4417L2.5 21.4998Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
)
}

export function CopiedCopier(props: { theme: 'light' | 'dark' }) {
return (
<svg
Expand Down

0 comments on commit 30007f9

Please sign in to comment.