Skip to content

Commit

Permalink
feat: enable editing on BigInt type (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
Azurewarth0920 authored Feb 3, 2024
1 parent a1ff8d9 commit 32746c5
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { toRaw } from 'vue'
import { VueButton, VueDropdown, VueDropdownButton, VueIcon, VTooltip as vTooltip } from '@vue/devtools-ui'
import { getRawValue } from '@vue/devtools-kit'
import { getRaw } from '@vue/devtools-kit'
import type { InspectorState, InspectorStateEditorPayload } from '@vue/devtools-kit'
import type { ButtonProps } from '@vue/devtools-ui/dist/types/src/components/Button'
import { useDevToolsBridgeRpc } from '@vue/devtools-core'
Expand Down Expand Up @@ -30,7 +30,9 @@ const { copy, isSupported } = useClipboard()
const popupVisible = ref(false)
const rawValue = computed(() => getRawValue(props.data.value).value)
const raw = computed(() => getRaw(props.data.value))
const rawValue = computed(() => raw.value.value)
const customType = computed(() => raw.value.customType)
const dataType = computed(() => typeof rawValue.value)
const iconButtonProps = {
Expand All @@ -56,6 +58,13 @@ function quickEdit(v: unknown, remove: boolean = false) {
},
} satisfies InspectorStateEditorPayload)
}
function quickEditNum(v: number | string, offset: 1 | -1) {
const target = typeof v === 'number'
? v + offset
: BigInt(v) + BigInt(offset)
quickEdit(target)
}
</script>

<template>
Expand Down Expand Up @@ -94,14 +103,14 @@ function quickEdit(v: unknown, remove: boolean = false) {
<VueIcon :icon="rawValue ? 'i-material-symbols-check-box-sharp' : 'i-material-symbols-check-box-outline-blank-sharp'" />
</template>
</VueButton>
<!-- increment/decrement button, numeric value only -->
<template v-else-if="dataType === 'number'">
<VueButton v-bind="iconButtonProps" :class="buttonClass" @click.stop="quickEdit((rawValue as number) + 1)">
<!-- increment/decrement button, numeric/bigint -->
<template v-else-if="dataType === 'number' || customType === 'bigint'">
<VueButton v-bind="iconButtonProps" :class="buttonClass" @click.stop="quickEditNum(rawValue as number | string, 1)">
<template #icon>
<VueIcon icon="i-carbon-add" />
</template>
</VueButton>
<VueButton v-bind="iconButtonProps" :class="buttonClass" @click.stop="quickEdit((rawValue as number) - 1)">
<VueButton v-bind="iconButtonProps" :class="buttonClass" @click.stop="quickEditNum(rawValue as number | string, -1)">
<template #icon>
<VueIcon icon="i-carbon-subtract" />
</template>
Expand Down Expand Up @@ -129,7 +138,7 @@ function quickEdit(v: unknown, remove: boolean = false) {
<template #popper>
<div class="w160px py5px">
<VueDropdownButton
@click="copy(dataType === 'object' ? JSON.stringify(rawValue) : rawValue.toString())"
@click="copy(typeof rawValue === 'object' ? JSON.stringify(rawValue) : rawValue.toString())"
>
<template #icon>
<VueIcon icon="i-material-symbols-copy-all-rounded" class="mt4px" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup lang="ts">
import { VueButton, VueIcon, VueInput, VTooltip as vTooltip } from '@vue/devtools-ui'
import { debounce } from 'perfect-debounce'
import { toSubmit } from '@vue/devtools-kit'
import { customTypeEnums, toSubmit } from '@vue/devtools-kit'
const props = withDefaults(defineProps<{
modelValue: string
type: string // typeof value
customType?: customTypeEnums
showActions?: boolean
autoFocus?: boolean
}>(), {
Expand All @@ -15,7 +15,7 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
'cancel': []
'submit': [dataType: string]
'submit': []
'update:modelValue': [value: string]
}>()
Expand All @@ -28,14 +28,14 @@ watchEffect(() => {
if (escape.value)
emit('cancel')
else if (enter.value)
emit('submit', props.type)
emit('submit')
})
const value = useVModel(props, 'modelValue', emit)
function tryToParseJSONString(v: unknown) {
try {
toSubmit(v as string)
toSubmit(v as string, props.customType)
return true
}
catch {
Expand Down Expand Up @@ -67,7 +67,7 @@ watch(value, checkWarning())
<VueButton
v-tooltip="{
content: 'Enter to submit change',
}" size="mini" flat class="p2px!" @click.stop="$emit('submit', type)"
}" size="mini" flat class="p2px!" @click.stop="$emit('submit')"
>
<template #icon>
<VueIcon icon="i-material-symbols-save" />
Expand Down
28 changes: 14 additions & 14 deletions packages/client/src/components/inspector/InspectorStateField.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { InspectorCustomState, InspectorState, InspectorStateEditorPayload } from '@vue/devtools-kit'
import { isArray, isObject, sortByKey } from '@vue/devtools-shared'
import { formatInspectorStateValue, getInspectorStateValueType, getRawValue, toEdit, toSubmit } from '@vue/devtools-kit'
import { formatInspectorStateValue, getInspectorStateValueType, getRaw, toEdit, toSubmit } from '@vue/devtools-kit'
import { useDevToolsBridgeRpc } from '@vue/devtools-core'
import { VueButton, VueIcon, VTooltip as vTooltip } from '@vue/devtools-ui'
import Actions from './InspectorDataField/Actions.vue'
Expand Down Expand Up @@ -50,12 +50,12 @@ const normalizedValue = computed(() => {
}
})
const rawValue = computed(() => getRawValue(props.data.value))
const raw = computed(() => getRaw(props.data.value))
const limit = ref(STATE_FIELDS_LIMIT_SIZE)
const normalizedChildField = computed(() => {
const { value, inherit } = rawValue.value
const { value, inherit } = raw.value
let displayedValue: any[]
if (isArray(value)) {
const sliced = value.slice(0, limit.value)
Expand Down Expand Up @@ -86,7 +86,7 @@ const normalizedChildField = computed(() => {
})
const fieldsCount = computed(() => {
const { value } = rawValue.value
const { value } = raw.value
if (isArray(value))
return value.length
else if (isObject(value))
Expand All @@ -112,15 +112,15 @@ const { editingType, editing, editingText, toggleEditing, nodeId } = useStateEdi
watch(() => editing.value, (v) => {
if (v) {
const { value } = rawValue.value
editingText.value = toEdit(value)
const { value } = raw.value
editingText.value = toEdit(value, raw.value.customType)
}
else {
editingText.value = ''
}
})
function submit(dataType: string) {
function submit() {
const data = props.data
bridgeRpc.editInspectorState({
path: data.key.split('.'),
Expand All @@ -129,8 +129,8 @@ function submit(dataType: string) {
nodeId,
state: {
newKey: null!,
type: dataType,
value: toSubmit(editingText.value),
type: editingType.value,
value: toSubmit(editingText.value, raw.value.customType),
},
} satisfies InspectorStateEditorPayload)
toggleEditing()
Expand All @@ -142,7 +142,7 @@ const { addNewProp: addNewPropApi, draftingNewProp, resetDrafting } = useStateEd
function addNewProp(type: EditorAddNewPropType) {
if (!isExpanded.value)
toggleCollapse()
addNewPropApi(type, rawValue.value.value)
addNewPropApi(type, raw.value.value)
}
function submitDrafting() {
Expand Down Expand Up @@ -173,7 +173,7 @@ const { isHovering } = useHover(() => containerRef.value)
<div>
<span overflow-hidden text-ellipsis whitespace-nowrap state-key>{{ normalizedDisplayedKey }}</span>
<span mx-1>:</span>
<EditInput v-if="editing" v-model="editingText" :type="editingType" @cancel="toggleEditing" @submit="submit" />
<EditInput v-if="editing" v-model="editingText" :custom-type="raw.customType" @cancel="toggleEditing" @submit="submit" />
<template v-else>
<span :class="stateFormatClass">
<span v-html="normalizedValue" />
Expand All @@ -191,7 +191,7 @@ const { isHovering } = useHover(() => containerRef.value)
<ExpandIcon :value="isExpanded" absolute left--6 group-hover:text-white />
<span overflow-hidden text-ellipsis whitespace-nowrap state-key>{{ normalizedDisplayedKey }}</span>
<span mx-1>:</span>
<EditInput v-if="editing" v-model="editingText" :type="editingType" @cancel="toggleEditing" @submit="submit" />
<EditInput v-if="editing" v-model="editingText" :custom-type="raw.customType" @cancel="toggleEditing" @submit="submit" />
<template v-else>
<span :class="stateFormatClass">
<span v-html="normalizedValue" />
Expand All @@ -214,10 +214,10 @@ const { isHovering } = useHover(() => containerRef.value)
</VueButton>
<div v-if="draftingNewProp.enable" :style="{ paddingLeft: `${(depth + 1) * 15 + 4}px` }">
<span overflow-hidden text-ellipsis whitespace-nowrap state-key>
<EditInput v-model="draftingNewProp.key" type="string" :show-actions="false" />
<EditInput v-model="draftingNewProp.key" :show-actions="false" />
</span>
<span mx-1>:</span>
<EditInput v-model="draftingNewProp.value" type="string" :auto-focus="false" @cancel="resetDrafting" @submit="submitDrafting" />
<EditInput v-model="draftingNewProp.value" :auto-focus="false" @cancel="resetDrafting" @submit="submitDrafting" />
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as format from '../format'
import { customTypeEnums } from '../../types'
import { INFINITY, NAN, NEGATIVE_INFINITY, UNDEFINED } from '../constants'

describe('format: displayText and rawValue can be calculated by formatInspectorStateValue, getRawValue', () => {
describe('format: displayText and rawValue can be calculated by formatInspectorStateValue, getRaw', () => {
describe('type: literals', () => {
// eslint-disable-next-line test/consistent-test-it
test.each([
Expand All @@ -16,7 +17,7 @@ describe('format: displayText and rawValue can be calculated by formatInspectorS
{ literal: UNDEFINED, displayText: 'undefined' },
])('type: %s', (value) => {
const displayText = format.formatInspectorStateValue(value.literal)
const rawValue = format.getRawValue(value.literal).value
const rawValue = format.getRaw(value.literal).value

expect(displayText).toBe(value.displayText)
expect(rawValue).toBe(value.literal)
Expand All @@ -26,7 +27,7 @@ describe('format: displayText and rawValue can be calculated by formatInspectorS
it('type: plain object', () => {
const value = { foo: 'bar' }
const displayText = format.formatInspectorStateValue(value)
const rawValue = format.getRawValue(value).value
const rawValue = format.getRaw(value).value

expect(displayText).toBe('Object')
expect(rawValue).toEqual(value)
Expand All @@ -35,7 +36,7 @@ describe('format: displayText and rawValue can be calculated by formatInspectorS
it('type: array', () => {
const value = ['foo', { bar: 'baz' }]
const displayText = format.formatInspectorStateValue(value)
const rawValue = format.getRawValue(value).value
const rawValue = format.getRaw(value).value

expect(displayText).toBe('Array[2]')
expect(rawValue).toEqual(value)
Expand All @@ -45,7 +46,7 @@ describe('format: displayText and rawValue can be calculated by formatInspectorS
it('type: common custom', () => {
const value = { _custom: { displayText: 'custom-display', value: Symbol(123) } }
const displayText = format.formatInspectorStateValue(value)
const rawValue = format.getRawValue(value).value
const rawValue = format.getRaw(value).value

expect(displayText).toBe(value._custom.displayText)
expect(rawValue).toEqual(value._custom.value)
Expand All @@ -62,7 +63,7 @@ describe('format: displayText and rawValue can be calculated by formatInspectorS
}

const displayText = format.formatInspectorStateValue(value)
const rawValue = format.getRawValue(value).value
const rawValue = format.getRaw(value).value

expect(displayText).toBe(value._custom.value._custom.displayText)
expect(rawValue).toEqual(value._custom.value._custom.value)
Expand All @@ -87,8 +88,9 @@ describe('format: toEdit', () => {
{ value: { foo: NAN }, target: '{"foo":NaN}' },
{ value: { foo: NEGATIVE_INFINITY }, target: '{"foo":-Infinity}' },
{ value: { foo: UNDEFINED }, target: '{"foo":undefined}' },
{ value: '123', customType: 'bigint' as customTypeEnums, target: '123' },
])('value: $value will be deserialized to target', (value) => {
const deserialized = format.toEdit(value.value)
const deserialized = format.toEdit(value.value, value.customType)
expect(deserialized).toBe(value.target)
})
})
Expand All @@ -113,8 +115,9 @@ describe('format: toSubmit', () => {
{ value: '{"foo":undefined}', target: {} },
// Regex test: The token in key field kept untouched.
{ value: '{"undefined": NaN }', target: { undefined: Number.NaN } },
{ value: '123', customType: 'bigint' as customTypeEnums, target: BigInt(123) },
])('value: $value will be serialized to target', (value) => {
const serialized = format.toSubmit(value.value)
const serialized = format.toSubmit(value.value, value.customType)
expect(serialized).toStrictEqual(value.target)
})
})
16 changes: 8 additions & 8 deletions packages/devtools-kit/src/core/component/state/custom.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { InspectorState } from '../types'
import type { InspectorState, customTypeEnums } from '../types'
import { getComponentName, getInstanceName } from '../general/util'
import { processInstanceState } from './process'
import { escape, getSetupStateType, toRaw } from './util'
Expand All @@ -21,7 +21,7 @@ export function getFunctionDetails(func: Function) {
const name = typeof func.name === 'string' ? func.name : ''
return {
_custom: {
type: 'function',
type: 'function' satisfies customTypeEnums,
displayText: `<span style="opacity:.5;">function</span> ${escape(name)}${args}`,
tooltipText: string.trim() ? `<pre>${string}</pre>` : null,
},
Expand Down Expand Up @@ -64,7 +64,7 @@ export function getSetDetails(val: Set<unknown>) {
const list = Array.from(val)
return {
_custom: {
type: 'set',
type: 'set' satisfies customTypeEnums,
displayText: `Set[${list.length}]`,
value: list,
readOnly: true,
Expand Down Expand Up @@ -120,7 +120,7 @@ function namedNodeMapToObject(map: NamedNodeMap) {
export function getStoreDetails(store) {
return {
_custom: {
type: 'store',
type: 'store' satisfies customTypeEnums,
displayText: 'Store',
value: {
state: store.state,
Expand Down Expand Up @@ -179,7 +179,7 @@ export function getComponentDefinitionDetails(definition) {
}
return {
_custom: {
type: 'component-definition',
type: 'component-definition' satisfies customTypeEnums,
displayText: display,
tooltipText: 'Component definition',
...definition.__file
Expand All @@ -195,7 +195,7 @@ export function getHTMLElementDetails(value: HTMLElement) {
try {
return {
_custom: {
type: 'HTMLElement',
type: 'HTMLElement' satisfies customTypeEnums,
displayText: `<span class="opacity-30">&lt;</span><span class="text-blue-500">${value.tagName.toLowerCase()}</span><span class="opacity-30">&gt;</span>`,
value: namedNodeMapToObject(value.attributes),
},
Expand All @@ -204,7 +204,7 @@ export function getHTMLElementDetails(value: HTMLElement) {
catch (e) {
return {
_custom: {
type: 'HTMLElement',
type: 'HTMLElement' satisfies customTypeEnums,
displayText: `<span class="text-blue-500">${String(value)}</span>`,
},
}
Expand Down Expand Up @@ -232,7 +232,7 @@ export function getObjectDetails(object: Record<string, any>) {
if (typeof object.__asyncLoader === 'function') {
return {
_custom: {
type: 'component-definition',
type: 'component-definition' satisfies customTypeEnums,
display: 'Async component definition',
},
}
Expand Down
Loading

0 comments on commit 32746c5

Please sign in to comment.