mirror of
https://github.com/directus/directus.git
synced 2026-01-23 11:07:56 -05:00
Fix json serialization (#16558)
* fix copying json fields * fixed preset filter type * handling fallback in copyToClipboard function * add test * try parsing json content on paste Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>
This commit is contained in:
@@ -81,6 +81,7 @@ import FormFieldMenu from './form-field-menu.vue';
|
||||
import { formatFieldFunction } from '@/utils/format-field-function';
|
||||
import { useClipboard } from '@/composables/use-clipboard';
|
||||
import FormFieldRawEditor from './form-field-raw-editor.vue';
|
||||
import { parseJSON } from '@directus/shared/utils';
|
||||
|
||||
interface Props {
|
||||
field: Field;
|
||||
@@ -178,8 +179,12 @@ function useRaw() {
|
||||
async function pasteRaw() {
|
||||
const pastedValue = await pasteFromClipboard();
|
||||
if (!pastedValue) return;
|
||||
internalValue.value = pastedValue;
|
||||
emitValue(pastedValue);
|
||||
try {
|
||||
internalValue.value = parseJSON(pastedValue);
|
||||
} catch (e) {
|
||||
internalValue.value = pastedValue;
|
||||
}
|
||||
emitValue(internalValue.value);
|
||||
}
|
||||
|
||||
return { showRaw, copyRaw, pasteRaw, onRawValueSubmit };
|
||||
|
||||
124
app/src/composables/use-clipboard.test.ts
Normal file
124
app/src/composables/use-clipboard.test.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { GlobalMountOptions } from '@vue/test-utils/dist/types';
|
||||
import { afterEach, beforeAll, describe, expect, test, vi } from 'vitest';
|
||||
import { defineComponent, h, unref } from 'vue';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
import { useClipboard } from './use-clipboard';
|
||||
|
||||
vi.mock('@/utils/notify', () => ({
|
||||
notify: vi.fn(),
|
||||
}));
|
||||
|
||||
const i18n = createI18n({ legacy: false });
|
||||
|
||||
const global: GlobalMountOptions = {
|
||||
plugins: [i18n],
|
||||
};
|
||||
|
||||
const testComponent = defineComponent({
|
||||
setup() {
|
||||
return useClipboard();
|
||||
},
|
||||
render: () => h('div'),
|
||||
});
|
||||
|
||||
describe('useClipboard', () => {
|
||||
beforeAll(() => {
|
||||
vi.spyOn(i18n.global, 't').mockImplementation((key) => key as any);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ value: { writeText: vi.fn() }, expectedResult: true },
|
||||
{ value: {}, expectedResult: false },
|
||||
])('isCopySupported should be $expectedResult', ({ value, expectedResult }) => {
|
||||
Object.defineProperty(navigator, 'clipboard', { value, configurable: true });
|
||||
|
||||
const wrapper = mount(testComponent, { global });
|
||||
|
||||
expect(unref(wrapper.vm.isCopySupported)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ value: { readText: vi.fn() }, expectedResult: true },
|
||||
{ value: {}, expectedResult: false },
|
||||
])('isPasteSupported should be $expectedResult', ({ value, expectedResult }) => {
|
||||
Object.defineProperty(navigator, 'clipboard', { value, configurable: true });
|
||||
|
||||
const wrapper = mount(testComponent, { global });
|
||||
|
||||
expect(unref(wrapper.vm.isPasteSupported)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
test('copyToClipboard with string value returns true', async () => {
|
||||
Object.defineProperty(navigator, 'clipboard', { value: { writeText: vi.fn() }, configurable: true });
|
||||
const writeTextSpy = vi.spyOn(navigator.clipboard, 'writeText');
|
||||
const copyValue = 'test';
|
||||
|
||||
const wrapper = mount(testComponent, { global });
|
||||
|
||||
const isCopied = await wrapper.vm.copyToClipboard(copyValue);
|
||||
|
||||
expect(writeTextSpy).toHaveBeenCalledWith(copyValue);
|
||||
expect(isCopied).toBe(true);
|
||||
});
|
||||
|
||||
test('copyToClipboard with json value stringifies it and returns true', async () => {
|
||||
Object.defineProperty(navigator, 'clipboard', { value: { writeText: vi.fn() }, configurable: true });
|
||||
const writeTextSpy = vi.spyOn(navigator.clipboard, 'writeText');
|
||||
const copyValue = { test: 'value' };
|
||||
|
||||
const wrapper = mount(testComponent, { global });
|
||||
|
||||
const isCopied = await wrapper.vm.copyToClipboard(copyValue);
|
||||
|
||||
expect(writeTextSpy).toHaveBeenCalledWith(JSON.stringify(copyValue));
|
||||
expect(isCopied).toBe(true);
|
||||
});
|
||||
|
||||
test('copyToClipboard returns false when it fails', async () => {
|
||||
Object.defineProperty(navigator, 'clipboard', {
|
||||
value: { writeText: vi.fn().mockImplementation(() => Promise.reject()) },
|
||||
configurable: true,
|
||||
});
|
||||
const copyValue = 'test';
|
||||
|
||||
const wrapper = mount(testComponent, { global });
|
||||
|
||||
const isCopied = await wrapper.vm.copyToClipboard(copyValue);
|
||||
|
||||
expect(isCopied).toBe(false);
|
||||
});
|
||||
|
||||
test('pasteFromClipboard returns string when it succeeds', async () => {
|
||||
const testClipboardValue = 'test';
|
||||
|
||||
Object.defineProperty(navigator, 'clipboard', {
|
||||
value: { readText: vi.fn().mockReturnValue(testClipboardValue) },
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
const wrapper = mount(testComponent, { global });
|
||||
|
||||
const clipboardValue = await wrapper.vm.pasteFromClipboard();
|
||||
|
||||
expect(clipboardValue).toBe(testClipboardValue);
|
||||
});
|
||||
|
||||
test('pasteFromClipboard returns null when it fails', async () => {
|
||||
Object.defineProperty(navigator, 'clipboard', {
|
||||
value: { readText: vi.fn().mockImplementation(() => Promise.reject()) },
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
const wrapper = mount(testComponent, { global });
|
||||
|
||||
const clipboardValue = await wrapper.vm.pasteFromClipboard();
|
||||
|
||||
expect(clipboardValue).toBe(null);
|
||||
});
|
||||
});
|
||||
@@ -20,9 +20,10 @@ export function useClipboard() {
|
||||
|
||||
return { isCopySupported, isPasteSupported, copyToClipboard, pasteFromClipboard };
|
||||
|
||||
async function copyToClipboard(value: string, message?: Message): Promise<boolean> {
|
||||
async function copyToClipboard(value: any, message?: Message): Promise<boolean> {
|
||||
try {
|
||||
await navigator?.clipboard?.writeText(value);
|
||||
const valueString = typeof value === 'string' ? value : JSON.stringify(value);
|
||||
await navigator?.clipboard?.writeText(valueString);
|
||||
notify({
|
||||
title: message?.success ?? t('copy_raw_value_success'),
|
||||
});
|
||||
|
||||
@@ -528,7 +528,7 @@ function useForm() {
|
||||
{
|
||||
field: 'filter',
|
||||
name: t('filter'),
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
meta: {
|
||||
interface: 'system-filter',
|
||||
width: 'half',
|
||||
|
||||
Reference in New Issue
Block a user