diff --git a/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2m.vue b/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2m.vue index e02040b447..1e82e1106e 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2m.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2m.vue @@ -13,6 +13,7 @@ v-model="junctionCollection" :placeholder="$t('select_one')" :disabled="isExisting" + allow-other />
@@ -111,7 +112,7 @@ export default defineComponent({ value: field.field, disabled: state.relations[0].many_field === field.field || - field.schema?.is_primary_key || + field.schema?.is_primary_key || state.relations[1].many_field === field.field, })); }); diff --git a/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2o.vue b/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2o.vue index b894e02238..b4ca1aaad5 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2o.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/components/relationship-m2o.vue @@ -8,16 +8,32 @@
{{ $t('related_collection') }}
- + + +
- - - + + + @@ -31,7 +47,7 @@
{{ $t('corresponding_field_name') }}
- + @@ -66,17 +82,21 @@ export default defineComponent({ const collectionsStore = useCollectionsStore(); const fieldsStore = useFieldsStore(); - const { items, relatedPrimary } = useRelation(); + const { items } = useRelation(); const { hasCorresponding, correspondingField, correspondingLabel } = useCorresponding(); + const isNewCollection = computed(() => { + return collectionsStore.getCollection(state.relations[0].one_collection) === null; + }); + return { relations: state.relations, items, - relatedPrimary, hasCorresponding, correspondingField, correspondingLabel, fieldData: state.fieldData, + isNewCollection, }; function useRelation() { @@ -97,13 +117,7 @@ export default defineComponent({ })) ); - const relatedPrimary = computed(() => { - return state.relations[0].one_collection - ? fieldsStore.getPrimaryKeyFieldForCollection(state.relations[0].one_collection)?.field - : null; - }); - - return { items, relatedPrimary }; + return { items }; } function useCorresponding() { @@ -175,7 +189,7 @@ export default defineComponent({ gap: 20px 32px; margin-top: 48px; - .v-icon { + .arrow { --v-icon-color: var(--foreground-subdued); position: absolute; @@ -185,6 +199,10 @@ export default defineComponent({ } } +.v-list { + --v-list-item-content-font-family: var(--family-monospace); +} + .v-divider { margin: 48px 0; } diff --git a/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue b/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue index e3ea5445b6..b6c5bc1a40 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue @@ -66,8 +66,8 @@ import SetupDisplay from './components/display.vue'; import { i18n } from '@/lang'; import { isEmpty } from 'lodash'; import api from '@/api'; -import { Relation } from '@/types'; -import { useFieldsStore, useRelationsStore } from '@/stores/'; +import { Relation, Collection } from '@/types'; +import { useFieldsStore, useRelationsStore, useCollectionsStore } from '@/stores/'; import { Field } from '@/types'; import router from '@/router'; import useCollection from '@/composables/use-collection'; @@ -99,6 +99,7 @@ export default defineComponent({ }, }, setup(props) { + const collectionsStore = useCollectionsStore(); const fieldsStore = useFieldsStore(); const relationsStore = useRelationsStore(); @@ -190,7 +191,8 @@ export default defineComponent({ state.relations.length === 0 || isEmpty(state.relations[0].many_collection) || isEmpty(state.relations[0].many_field) || - isEmpty(state.relations[0].one_collection) + isEmpty(state.relations[0].one_collection) || + isEmpty(state.relations[0].one_primary) ); } @@ -224,6 +226,12 @@ export default defineComponent({ await api.post(`/fields/${props.collection}`, state.fieldData); } + await Promise.all( + state.newCollections.map((newCollection: Partial) => { + return api.post(`/collections`, newCollection); + }) + ); + await Promise.all( state.newFields.map((newField: Partial) => { return api.post(`/fields/${newField.collection}`, newField); @@ -240,6 +248,7 @@ export default defineComponent({ }) ); + await collectionsStore.hydrate(); await fieldsStore.hydrate(); await relationsStore.hydrate(); diff --git a/app/src/modules/settings/routes/data-model/field-detail/store.ts b/app/src/modules/settings/routes/data-model/field-detail/store.ts index e3b31e02c2..ff8898e863 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/store.ts +++ b/app/src/modules/settings/routes/data-model/field-detail/store.ts @@ -5,9 +5,9 @@ * It's reset every time the modal opens and shouldn't be used outside of the field-detail flow. */ -import { useFieldsStore, useRelationsStore } from '@/stores/'; +import { useFieldsStore, useRelationsStore, useCollectionsStore } from '@/stores/'; import { reactive, watch, computed, ComputedRef } from '@vue/composition-api'; -import { clone } from 'lodash'; +import { clone, throttle } from 'lodash'; import { getInterfaces } from '@/interfaces'; import { getDisplays } from '@/displays'; import { InterfaceConfig } from '@/interfaces/types'; @@ -27,6 +27,7 @@ function initLocalStore( field: string, type: 'standard' | 'file' | 'files' | 'm2o' | 'o2m' | 'm2m' | 'presentation' ) { + const collectionsStore = useCollectionsStore(); const interfaces = getInterfaces(); const displays = getDisplays(); @@ -51,6 +52,7 @@ function initLocalStore( }, }, relations: [], + newCollections: [], newFields: [], }); @@ -141,7 +143,33 @@ function initLocalStore( } if (type === 'm2o') { - if (!isExisting) { + const syncNewCollectionsM2O = throttle(() => { + const collectionName = state.relations[0].one_collection; + + if (collectionExists(collectionName)) { + state.newCollections = []; + } else { + state.newCollections = [ + { + collection: collectionName, + fields: [ + { + field: state.relations[0].one_primary, + type: 'integer', + schema: { + has_auto_increment: true, + }, + system: { + interface: 'text-input', + } + } + ] + } + ]; + } + }, 50); + + if (isExisting === false) { state.relations = [ { many_collection: collection, @@ -165,9 +193,13 @@ function initLocalStore( watch( () => state.relations[0].one_collection, () => { - const field = fieldsStore.getPrimaryKeyFieldForCollection(state.relations[0].one_collection); - state.fieldData.type = field.type; - state.relations[0].one_primary = field.field; + if (collectionExists(state.relations[0].one_collection)) { + const field = fieldsStore.getPrimaryKeyFieldForCollection(state.relations[0].one_collection); + state.fieldData.type = field.type; + state.relations[0].one_primary = field.field; + } else { + state.fieldData.type = 'integer'; + } } ); @@ -180,6 +212,8 @@ function initLocalStore( } } ); + + watch([() => state.relations[0].one_collection, () => state.relations[0].one_primary], syncNewCollectionsM2O); } if (type === 'o2m') { @@ -322,6 +356,10 @@ function initLocalStore( } ); } + + function collectionExists(collection: string) { + return collectionsStore.getCollection(collection) !== null; + } } function clearLocalStore() {