mirror of
https://github.com/directus/directus.git
synced 2026-02-11 10:14:54 -05:00
@@ -35,6 +35,7 @@ export default function (
|
||||
emit('beforeEnter');
|
||||
|
||||
el._parent = el.parentNode as (Node & ParentNode & HTMLElement) | null;
|
||||
|
||||
el._initialStyle = {
|
||||
transition: el.style.transition,
|
||||
visibility: el.style.visibility,
|
||||
@@ -84,6 +85,7 @@ export default function (
|
||||
emit('beforeLeave');
|
||||
|
||||
el._parent = el.parentNode as (Node & ParentNode & HTMLElement) | null;
|
||||
|
||||
el._initialStyle = {
|
||||
transition: el.style.transition,
|
||||
visibility: el.style.visibility,
|
||||
|
||||
@@ -23,6 +23,7 @@ beforeEach(async () => {
|
||||
component: h('div', 'empty'),
|
||||
},
|
||||
]);
|
||||
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ beforeEach(async () => {
|
||||
component: h('div', 'empty'),
|
||||
},
|
||||
]);
|
||||
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ const emojiPicker = new EmojiButton({
|
||||
position: 'bottom',
|
||||
emojisPerRow: 8,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['emoji-selected']);
|
||||
|
||||
emojiPicker.on('emoji', (event) => {
|
||||
|
||||
@@ -44,6 +44,7 @@ test('Should show fallback component when there is an error', async () => {
|
||||
},
|
||||
render: () => h('div', 'test'),
|
||||
});
|
||||
|
||||
const fallbackComponent = defineComponent({ render: () => h('div', 'fallback') });
|
||||
|
||||
const wrapper = mount(VErrorBoundary, {
|
||||
|
||||
@@ -47,9 +47,11 @@ const { isCopySupported, copyToClipboard } = useClipboard();
|
||||
|
||||
async function copyError() {
|
||||
const error = props.error?.response?.data || props.error;
|
||||
|
||||
const isCopied = await copyToClipboard(
|
||||
JSON.stringify(error, isPlainObject(error) ? null : Object.getOwnPropertyNames(error), 2)
|
||||
);
|
||||
|
||||
if (!isCopied) return;
|
||||
copied.value = true;
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ function filter(field: Field, parent?: FieldNode): boolean {
|
||||
const children = isNil(field.schema?.foreign_key_table)
|
||||
? fieldsStore.getFieldGroupChildren(field.collection, field.field)
|
||||
: fieldsStore.getFieldsForCollection(field.schema!.foreign_key_table);
|
||||
|
||||
return children?.some((field) => matchesSearch(field)) || matchesSearch(field);
|
||||
|
||||
function matchesSearch(field: Field) {
|
||||
|
||||
@@ -288,6 +288,7 @@ function setContent() {
|
||||
}</button>`;
|
||||
})
|
||||
.join('');
|
||||
|
||||
contentEl.value.innerHTML = newInnerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,14 @@ test('should render', () => {
|
||||
},
|
||||
global,
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// test if there is a value
|
||||
test('submitting', async () => {
|
||||
expect(formFieldRawEditor).toBeTruthy();
|
||||
|
||||
const wrapper = mount(formFieldRawEditor, {
|
||||
props: {
|
||||
showModal: true,
|
||||
@@ -38,6 +40,7 @@ test('submitting', async () => {
|
||||
},
|
||||
global,
|
||||
});
|
||||
|
||||
const button = wrapper.findAll('v-button').at(1);
|
||||
await button!.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
@@ -54,6 +57,7 @@ it('should cancel with keydown', async () => {
|
||||
},
|
||||
global,
|
||||
});
|
||||
|
||||
await wrapper.trigger('esc');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.emitted().cancel.length).toBe(1);
|
||||
@@ -69,6 +73,7 @@ it('should cancel with the cancel button', async () => {
|
||||
},
|
||||
global,
|
||||
});
|
||||
|
||||
const button = wrapper.findAll('v-button').at(0);
|
||||
await button!.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
@@ -179,6 +179,7 @@ function useRaw() {
|
||||
async function pasteRaw() {
|
||||
const pastedValue = await pasteFromClipboard();
|
||||
if (!pastedValue) return;
|
||||
|
||||
try {
|
||||
internalValue.value = parseJSON(pastedValue);
|
||||
} catch (e) {
|
||||
@@ -194,6 +195,7 @@ function useRaw() {
|
||||
function useComputedValues() {
|
||||
const defaultValue = computed<any>(() => props.field?.schema?.default_value);
|
||||
const internalValue = ref<any>(getInternalValue());
|
||||
|
||||
const isEdited = computed(
|
||||
() => props.modelValue !== undefined && isEqual(props.modelValue, props.initialValue) === false
|
||||
);
|
||||
|
||||
@@ -251,6 +251,7 @@ function useForm() {
|
||||
(field: Field) => field.meta?.group === props.group || (props.group === null && isNil(field.meta?.group))
|
||||
)
|
||||
);
|
||||
|
||||
const fieldNames = computed(() => {
|
||||
return fieldsInGroup.value.map((f) => f.field);
|
||||
});
|
||||
@@ -342,6 +343,7 @@ function apply(updates: { [field: string]: any }) {
|
||||
const groupFields = getFieldsForGroup(props.group)
|
||||
.filter((field) => !field.schema?.is_primary_key && !isDisabled(field))
|
||||
.map((field) => field.field);
|
||||
|
||||
emit('update:modelValue', assign({}, omit(props.modelValue, groupFields), pick(updates, updatableKeys)));
|
||||
} else {
|
||||
emit('update:modelValue', pick(assign({}, props.modelValue, updates), updatableKeys));
|
||||
@@ -366,6 +368,7 @@ function useBatch() {
|
||||
|
||||
function toggleBatchField(field: Field | undefined) {
|
||||
if (!field) return;
|
||||
|
||||
if (batchActiveFields.value.includes(field.field)) {
|
||||
batchActiveFields.value = batchActiveFields.value.filter((fieldKey) => fieldKey !== field.field);
|
||||
|
||||
@@ -390,6 +393,7 @@ function useRawEditor() {
|
||||
|
||||
function toggleRawField(field: Field | undefined) {
|
||||
if (!field) return;
|
||||
|
||||
if (rawActiveFields.value.has(field.field)) {
|
||||
rawActiveFields.value.delete(field.field);
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,7 @@ const imageElement = ref<HTMLImageElement>();
|
||||
|
||||
const emptyPixel =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
|
||||
|
||||
const srcData = ref<string>(emptyPixel);
|
||||
|
||||
const observer = new IntersectionObserver((entries, observer) => {
|
||||
@@ -31,6 +32,7 @@ const observer = new IntersectionObserver((entries, observer) => {
|
||||
loadImage();
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.src,
|
||||
() => {
|
||||
|
||||
@@ -151,6 +151,7 @@ const listeners = computed(() => ({
|
||||
},
|
||||
focus: (e: PointerEvent) => emit('focus', e),
|
||||
}));
|
||||
|
||||
const attributes = computed(() => omit(attrs, ['class']));
|
||||
|
||||
const classes = computed(() => [
|
||||
|
||||
@@ -32,6 +32,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const { modelValue: selection, multiple, max, mandatory } = toRefs(props);
|
||||
|
||||
useGroupableParent(
|
||||
{
|
||||
selection: selection,
|
||||
|
||||
@@ -27,6 +27,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
});
|
||||
|
||||
const { active } = toRefs(props);
|
||||
|
||||
const { active: isActive, toggle } = useGroupable({
|
||||
value: props.value,
|
||||
group: props.scope,
|
||||
|
||||
@@ -242,6 +242,7 @@ function onClickOutsideMiddleware(e: Event) {
|
||||
|
||||
function onContentClick(e: Event) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (e.target !== e.currentTarget) {
|
||||
deactivate();
|
||||
}
|
||||
@@ -329,7 +330,9 @@ function usePopper(
|
||||
modifiers: getModifiers(resolve),
|
||||
strategy: 'fixed',
|
||||
});
|
||||
|
||||
popperInstance.value.forceUpdate();
|
||||
|
||||
observer.observe(popper.value!, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { createI18n } from 'vue-i18n';
|
||||
import { Focus } from '@/__utils__/focus';
|
||||
|
||||
const i18n = createI18n({ legacy: false });
|
||||
|
||||
const global: GlobalMountOptions = {
|
||||
stubs: [
|
||||
'v-list',
|
||||
|
||||
@@ -218,9 +218,11 @@ const { t } = useI18n();
|
||||
const { internalItems, internalItemsCount, internalSearch } = useItems();
|
||||
const { displayValue } = useDisplayValue();
|
||||
const { modelValue } = toRefs(props);
|
||||
|
||||
const { otherValue, usesOtherValue } = useCustomSelection(modelValue as Ref<string>, internalItems, (value) =>
|
||||
emit('update:modelValue', value)
|
||||
);
|
||||
|
||||
const { otherValues, addOtherValue, setOtherValue } = useCustomSelectionMultiple(
|
||||
modelValue as Ref<string[]>,
|
||||
internalItems,
|
||||
@@ -228,6 +230,7 @@ const { otherValues, addOtherValue, setOtherValue } = useCustomSelectionMultiple
|
||||
);
|
||||
|
||||
const search = ref<string | null>(null);
|
||||
|
||||
watch(
|
||||
search,
|
||||
debounce((val: string | null) => {
|
||||
|
||||
@@ -233,6 +233,7 @@ function onMouseMove(event: PointerEvent) {
|
||||
if (resizing.value === true) {
|
||||
const newWidth = resizeStartWidth.value + (event.pageX - resizeStartX.value);
|
||||
const currentHeaders = clone(props.headers);
|
||||
|
||||
const newHeaders = currentHeaders.map((existing: Header) => {
|
||||
if (existing.value === resizeHeader.value?.value) {
|
||||
return {
|
||||
@@ -243,6 +244,7 @@ function onMouseMove(event: PointerEvent) {
|
||||
|
||||
return existing;
|
||||
});
|
||||
|
||||
emit('update:headers', newHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,6 +298,7 @@ function getSelectedState(item: Item) {
|
||||
const selectedKeys = props.selectionUseKeys
|
||||
? props.modelValue
|
||||
: props.modelValue.map((item: any) => item[props.itemKey]);
|
||||
|
||||
return selectedKeys.includes(item[props.itemKey]);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ function checkKeyDown(event: any) {
|
||||
input.value!.innerText.substring(caretPos),
|
||||
true
|
||||
);
|
||||
|
||||
position(input.value!, caretPos + 1);
|
||||
}
|
||||
} else if (event.code === 'ArrowUp' && !event.shiftKey) {
|
||||
@@ -123,6 +124,7 @@ function checkKeyDown(event: any) {
|
||||
event.preventDefault();
|
||||
|
||||
const newCaretPos = matchedPositions[checkCaretPos - 1];
|
||||
|
||||
parseHTML(
|
||||
(input.value!.innerText.substring(0, newCaretPos) + input.value!.innerText.substring(caretPos)).replaceAll(
|
||||
String.fromCharCode(160),
|
||||
@@ -130,6 +132,7 @@ function checkKeyDown(event: any) {
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
position(input.value!, newCaretPos);
|
||||
emit('update:modelValue', input.value!.innerText);
|
||||
}
|
||||
@@ -146,6 +149,7 @@ function checkKeyDown(event: any) {
|
||||
).replaceAll(String.fromCharCode(160), ' '),
|
||||
true
|
||||
);
|
||||
|
||||
position(input.value!, caretPos);
|
||||
emit('update:modelValue', input.value!.innerText);
|
||||
}
|
||||
@@ -257,6 +261,7 @@ function parseHTML(innerText?: string, isDirectInput = false) {
|
||||
}
|
||||
|
||||
let searchString = replaceSpaceBefore + match + replaceSpaceAfter;
|
||||
|
||||
let replacementString = `${addSpaceBefore}<mark class="preview" data-preview="${
|
||||
props.items[match.substring(props.triggerCharacter.length)]
|
||||
}" contenteditable="false">${match}</mark>${addSpaceAfter}`;
|
||||
@@ -280,6 +285,7 @@ function parseHTML(innerText?: string, isDirectInput = false) {
|
||||
}
|
||||
|
||||
lastMatchIndex = 0;
|
||||
|
||||
for (const match of matches ?? []) {
|
||||
let matchIndex = input.value.innerText.indexOf(match, lastMatchIndex);
|
||||
matchedPositions.push(matchIndex, matchIndex + match.length);
|
||||
|
||||
@@ -131,6 +131,7 @@ const filterByFolder = computed(() => {
|
||||
|
||||
function validFiles(files: FileList) {
|
||||
if (files.length === 0) return false;
|
||||
|
||||
for (const file of files) {
|
||||
if (file.size === 0) return false;
|
||||
}
|
||||
@@ -162,6 +163,7 @@ function useUpload() {
|
||||
}
|
||||
|
||||
numberOfFiles.value = files.length;
|
||||
|
||||
if (props.multiple === true) {
|
||||
const uploadedFiles = await uploadFiles(Array.from(files), {
|
||||
onProgressChange: (percentage) => {
|
||||
|
||||
@@ -306,6 +306,7 @@ function useDragDrop() {
|
||||
|
||||
function onPointerUp() {
|
||||
dragging.value = false;
|
||||
|
||||
if (
|
||||
props.editMode === false ||
|
||||
props.draggable === false ||
|
||||
|
||||
Reference in New Issue
Block a user