This commit is contained in:
rijkvanzanten
2020-07-24 10:36:19 -04:00
parent 13fa2ed4b6
commit a4e788507b
4 changed files with 249 additions and 22 deletions

View File

@@ -51,8 +51,13 @@
"not_available_for_type": "Not Available for this Type",
"configure_m2o": "Configure your Many-to-One Relationship...",
"configure_o2m": "Configure your One-to-Many Relationship...",
"configure_m2m": "Configure your Many-to-Many Relationship...",
"add_m2o_to_collection": "Add Many-to-One to \"{collection}\"",
"add_o2m_to_collection": "Add One-to-Many to \"{collection}\"",
"add_m2m_to_collection": "Add Many-to-Many to \"{collection}\"",
"choose_a_type": "Choose a Type...",
"determined_by_relationship": "Determined by Relationship",

View File

@@ -24,7 +24,7 @@
<div class="grid">
<div class="field">
<div class="type-label">{{ $t('create_corresponding_field') }}</div>
<v-checkbox block :label="$t('add_field_related')" v-model="hasCorresponding" />
<v-checkbox block :label="correspondingLabel" v-model="hasCorresponding" />
</div>
<div class="field">
<div class="type-label">{{ $t('corresponding_field_name') }}</div>
@@ -43,6 +43,7 @@ import { orderBy } from 'lodash';
import useSync from '@/composables/use-sync';
import useCollectionsStore from '@/stores/collections';
import useFieldsStore from '@/stores/fields';
import i18n from '@/lang';
export default defineComponent({
props: {
@@ -75,9 +76,17 @@ export default defineComponent({
const fieldsStore = useFieldsStore();
const { items, relatedPrimary } = useRelation();
const { hasCorresponding, correspondingField } = useCorresponding();
const { hasCorresponding, correspondingField, correspondingLabel } = useCorresponding();
return { _relations, _newFields, items, relatedPrimary, hasCorresponding, correspondingField };
return {
_relations,
_newFields,
items,
relatedPrimary,
hasCorresponding,
correspondingField,
correspondingLabel,
};
function useRelation() {
const availableCollections = computed(() => {
@@ -132,21 +141,6 @@ export default defineComponent({
},
});
watch(
() => _relations.value[0].collection_one,
() => {
if (hasCorresponding.value === true) {
_newFields.value = [
{
...(_newFields.value[0] || {}),
collection: _relations.value[0].collection_one,
},
];
}
},
{ immediate: true }
);
const correspondingField = computed({
get() {
return _newFields.value?.[0]?.field || null;
@@ -168,7 +162,15 @@ export default defineComponent({
},
});
return { hasCorresponding, correspondingField };
const correspondingLabel = computed(() => {
if (_relations.value[0].collection_one) {
return i18n.t('add_o2m_to_collection', { collection: _relations.value[0].collection_one });
}
return i18n.t('add_field_related');
});
return { hasCorresponding, correspondingField, correspondingLabel };
}
},
});

View File

@@ -1,9 +1,181 @@
<template>
<div>O2M</div>
<div>
<h2 class="type-title">{{ $t('configure_o2m') }}</h2>
<div class="grid">
<div class="field">
<div class="type-label">{{ $t('this_collection') }}</div>
<v-input disabled :value="collection" />
</div>
<div class="field">
<div class="type-label">{{ $t('related_collection') }}</div>
<v-select :placeholder="$t('choose_a_collection')" :items="items" v-model="collectionMany" />
</div>
<v-input disabled :value="currentCollectionPrimaryKey.field" />
<v-select
v-model="_relations[0].field_many"
:disabled="!_relations[0].collection_many"
:items="fields"
:placeholder="!_relations[0].collection_many ? $t('choose_a_collection') : $t('choose_a_field')"
/>
<v-icon name="arrow_forward" />
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
import { defineComponent, PropType, computed } from '@vue/composition-api';
import { Relation } from '@/stores/relations/types';
import { Field } from '@/stores/fields/types';
import useSync from '@/composables/use-sync';
import useCollectionsStore from '@/stores/collections';
import useFieldsStore from '@/stores/fields';
import { orderBy } from 'lodash';
import i18n from '@/lang';
export default defineComponent({});
export default defineComponent({
props: {
type: {
type: String,
required: true,
},
relations: {
type: Array as PropType<Relation[]>,
required: true,
},
newFields: {
type: Array as PropType<DeepPartial<Field>[]>,
required: true,
},
fieldData: {
type: Object,
required: true,
},
collection: {
type: String,
required: true,
},
},
setup(props, { emit }) {
const _relations = useSync(props, 'relations', emit);
const _newFields = useSync(props, 'newFields', emit);
const collectionsStore = useCollectionsStore();
const fieldsStore = useFieldsStore();
const { items, fields, currentCollectionPrimaryKey, collectionMany } = useRelation();
return { _relations, items, fields, currentCollectionPrimaryKey, collectionMany };
function useRelation() {
const availableCollections = computed(() => {
return orderBy(
collectionsStore.state.collections.filter((collection) => {
return (
collection.collection.startsWith('directus_') === false &&
collection.collection !== props.collection
);
}),
['collection'],
['asc']
);
});
const items = computed(() =>
availableCollections.value.map((collection) => ({
text: collection.collection,
value: collection.collection,
}))
);
const currentCollectionPrimaryKey = computed(() =>
fieldsStore.getPrimaryKeyFieldForCollection(props.collection)
);
const fields = computed(() => {
if (!_relations.value[0].collection_many) return [];
return fieldsStore.state.fields
.filter((field) => {
if (field.collection !== _relations.value[0].collection_many) return false;
// Make sure the selected field matches the type of primary key of the current
// collection. Otherwise you aren't able to properly save the primary key
if (!field.database || field.database.type !== currentCollectionPrimaryKey.value.database.type)
return false;
return true;
})
.map((field) => field.field);
});
const collectionMany = computed({
get() {
return _relations.value[0].collection_many;
},
set(collection: string) {
_relations.value[0].collection_many = collection;
_relations.value[0].field_many = '';
},
});
return { availableCollections, items, fields, currentCollectionPrimaryKey, collectionMany };
}
function useCorresponding() {
const hasCorresponding = computed({
get() {
return _newFields.value.length > 0;
},
set(enabled: boolean) {
if (enabled === true) {
_newFields.value = [
{
field: _relations.value[0].field_many,
collection: _relations.value[0].collection_many,
system: {
interface: 'many-to-one',
},
},
];
} else {
_newFields.value = [];
}
},
});
const correspondingLabel = computed(() => {
if (_relations.value[0].collection_many) {
return i18n.t('add_m2o_to_collection', { collection: _relations.value[0].collection_many });
}
return i18n.t('add_field_related');
});
return { hasCorresponding, correspondingLabel };
}
},
});
</script>
<style lang="scss" scoped>
.grid {
position: relative;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px 32px;
margin-top: 48px;
.v-icon {
--v-icon-color: var(--foreground-subdued);
position: absolute;
bottom: 14px;
left: 50%;
transform: translateX(-50%);
}
}
.type-label {
margin-bottom: 8px;
}
</style>

View File

@@ -60,6 +60,7 @@ import api from '@/api';
import { Relation } from '@/stores/relations/types';
import { useFieldsStore } from '@/stores/fields';
import { Field } from '@/stores/fields/types';
import router from '@/router';
export default defineComponent({
components: {
@@ -244,11 +245,56 @@ export default defineComponent({
fieldData.database.type = field.database.type;
}
);
watch(
() => relations.value[0].collection_one,
() => {
if (newFields.value.length > 0) {
newFields.value[0].collection = relations.value[0].collection_one;
}
}
);
}
if (props.type === 'o2m') {
delete fieldData.database;
fieldData.system.special = 'o2m';
relations.value = [
{
collection_many: '',
field_many: '',
primary_many: '',
collection_one: props.collection,
field_one: fieldData.field,
primary_one: fieldsStore.getPrimaryKeyFieldForCollection(props.collection)?.field,
},
];
watch(
() => fieldData.field,
() => {
relations.value[0].field_one = fieldData.field;
}
);
watch(
() => relations.value[0].collection_many,
() => {
relations.value[0].primary_many = fieldsStore.getPrimaryKeyFieldForCollection(
relations.value[0].collection_many
).field;
}
);
}
if (props.type === 'm2m' || props.type === 'files') {
delete fieldData.database;
fieldData.system.special = 'm2m';
relations.value = [
{
collection_many: '',
@@ -319,6 +365,8 @@ export default defineComponent({
);
await api.post(`/relations`, relations.value);
router.push(`/settings/data-model/${props.collection}`);
} catch (error) {
console.error(error);
} finally {