mirror of
https://github.com/directus/directus.git
synced 2026-01-30 07:58:15 -05:00
Merge pull request #287 from directus/suggest-m2o
suggest fields on m2o
This commit is contained in:
@@ -27,7 +27,7 @@ export default async function runAST(originalAST: AST, options?: RunASTOptions):
|
||||
|
||||
const rawItems: Item | Item[] = await dbQuery;
|
||||
|
||||
if (!rawItems || (Array.isArray(rawItems) && rawItems.length === 0)) return null;
|
||||
if (!rawItems) return null;
|
||||
|
||||
// Run the items through the special transforms
|
||||
const payloadService = new PayloadService(ast.name, { knex });
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
:key="childField.field"
|
||||
:parent="`${parent ? parent + '.' : ''}${field.field}`"
|
||||
:field="childField"
|
||||
:depth="depth - 1"
|
||||
@add="$emit('add', $event)"
|
||||
/>
|
||||
</v-list-group>
|
||||
@@ -33,6 +34,10 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
depth: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</template>
|
||||
|
||||
<v-list dense>
|
||||
<field-list-item @add="addField" v-for="field in tree" :key="field.field" :field="field" />
|
||||
<field-list-item @add="addField" v-for="field in tree" :key="field.field" :field="field" :depth="depth" />
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
@@ -33,6 +33,7 @@ import FieldListItem from './field-list-item.vue';
|
||||
import { useFieldsStore } from '@/stores';
|
||||
import { Field } from '@/types/';
|
||||
import useFieldTree from '@/composables/use-field-tree';
|
||||
import { FieldTree } from './types';
|
||||
|
||||
export default defineComponent({
|
||||
components: { FieldListItem },
|
||||
@@ -49,6 +50,10 @@ export default defineComponent({
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
depth: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const fieldsStore = useFieldsStore();
|
||||
@@ -149,7 +154,9 @@ export default defineComponent({
|
||||
|
||||
function addField(fieldKey: string) {
|
||||
if (!contentEl.value) return;
|
||||
const field: Field | null = fieldsStore.getField(props.collection, fieldKey);
|
||||
|
||||
const field = findTree(tree.value, fieldKey.split('.'));
|
||||
|
||||
if (!field) return;
|
||||
|
||||
const button = document.createElement('button');
|
||||
@@ -157,6 +164,12 @@ export default defineComponent({
|
||||
button.setAttribute('contenteditable', 'false');
|
||||
button.innerText = String(field.name);
|
||||
|
||||
if (window.getSelection()?.rangeCount == 0) {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(contentEl.value.children[0]);
|
||||
window.getSelection()?.addRange(range);
|
||||
}
|
||||
|
||||
const range = window.getSelection()?.getRangeAt(0);
|
||||
if (!range) return;
|
||||
range.deleteContents();
|
||||
@@ -176,6 +189,16 @@ export default defineComponent({
|
||||
onInput();
|
||||
}
|
||||
|
||||
function findTree(tree: FieldTree[] | undefined, fieldSections: string[]): FieldTree | undefined {
|
||||
if (tree === undefined) return undefined;
|
||||
|
||||
const fieldObject = tree.find((f) => f.field === fieldSections[0]);
|
||||
|
||||
if (fieldObject === undefined) return undefined;
|
||||
if (fieldSections.length === 1) return fieldObject;
|
||||
return findTree(fieldObject.children, fieldSections.slice(1));
|
||||
}
|
||||
|
||||
function joinElements(first: HTMLElement, second: HTMLElement) {
|
||||
first.innerText += second.innerText;
|
||||
second.remove();
|
||||
@@ -241,7 +264,7 @@ export default defineComponent({
|
||||
return `<span class="text">${part}</span>`;
|
||||
}
|
||||
const fieldKey = part.replaceAll(/({|})/g, '').trim();
|
||||
const field: Field | null = fieldsStore.getField(props.collection, fieldKey);
|
||||
const field = findTree(tree.value, fieldKey.split('.'));
|
||||
|
||||
if (!field) return '';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import useFieldTree from './use-field-tree';
|
||||
import useFieldTree, { filterTree, findTree } from './use-field-tree';
|
||||
|
||||
export default useFieldTree;
|
||||
export { useFieldTree };
|
||||
export { useFieldTree, filterTree, findTree };
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function useFieldTree(collection: Ref<string>, showHidden = false
|
||||
.filter((field: Field) => {
|
||||
let shown = (field.meta?.special || []).includes('alias') === false;
|
||||
|
||||
if (showHidden === false && field.meta?.hidden === false) {
|
||||
if (showHidden === false && field.meta?.hidden === true) {
|
||||
shown = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { defineInterface } from '../define';
|
||||
import InterfaceManyToOne from './many-to-one.vue';
|
||||
import Options from './options.vue';
|
||||
|
||||
export default defineInterface(({ i18n }) => ({
|
||||
id: 'many-to-one',
|
||||
@@ -9,16 +10,6 @@ export default defineInterface(({ i18n }) => ({
|
||||
component: InterfaceManyToOne,
|
||||
types: ['uuid', 'string', 'text', 'integer', 'bigInteger'],
|
||||
relationship: 'm2o',
|
||||
options: [
|
||||
{
|
||||
field: 'template',
|
||||
name: i18n.t('interfaces.many-to-one.display_template'),
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
},
|
||||
},
|
||||
],
|
||||
options: Options,
|
||||
recommendedDisplays: ['related-values'],
|
||||
}));
|
||||
|
||||
71
app/src/interfaces/many-to-one/options.vue
Normal file
71
app/src/interfaces/many-to-one/options.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<v-notice class="full" type="warning" v-if="collection === null">
|
||||
{{ $t('interfaces.one-to-many.no_collection') }}
|
||||
</v-notice>
|
||||
<div v-else class="form-grid">
|
||||
<div class="field full">
|
||||
<p class="type-label">{{ $t('interfaces.many-to-one.display_template') }}</p>
|
||||
<v-field-template :collection="relatedCollection" v-model="template" :depth="2"></v-field-template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Field } from '@/types';
|
||||
import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import { useRelationsStore } from '@/stores/';
|
||||
import { Relation } from '@/types/relations';
|
||||
export default defineComponent({
|
||||
props: {
|
||||
collection: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
fieldData: {
|
||||
type: Object as PropType<Field>,
|
||||
default: null,
|
||||
},
|
||||
relations: {
|
||||
type: Array as PropType<Relation[]>,
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
type: Object as PropType<any>,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const relationsStore = useRelationsStore();
|
||||
const template = computed({
|
||||
get() {
|
||||
return props.value?.template;
|
||||
},
|
||||
set(newTemplate: string) {
|
||||
emit('input', {
|
||||
...(props.value || {}),
|
||||
template: newTemplate,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const relatedCollection = computed(() => {
|
||||
if (!props.fieldData || !props.relations || props.relations.length === 0) return null;
|
||||
const { field } = props.fieldData;
|
||||
const relation = props.relations.find(
|
||||
(relation) => relation.many_collection === props.collection && relation.many_field === field
|
||||
);
|
||||
return relation?.one_collection || null;
|
||||
});
|
||||
|
||||
return { template, relatedCollection };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/mixins/form-grid';
|
||||
|
||||
.form-grid {
|
||||
@include form-grid;
|
||||
}
|
||||
</style>
|
||||
@@ -52,7 +52,7 @@ export const useRelationsStore = createStore({
|
||||
] as Relation[];
|
||||
}
|
||||
|
||||
const relations = this.getRelationsForCollection(collection).filter((relation: Relation) => {
|
||||
const relations: Relation[] = this.getRelationsForCollection(collection).filter((relation: Relation) => {
|
||||
return relation.many_field === field || relation.one_field === field;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user