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 1e82e1106e..2fe8c1b777 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
@@ -4,45 +4,108 @@
{{ $t('this_collection') }}
-
+
{{ $t('junction_collection') }}
-
+
+
+
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
{{ $t('related_collection') }}
-
+
+
+
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
+
+
+
@@ -104,6 +167,14 @@ export default defineComponent({
},
});
+ const junctionCollectionExists = computed(() => {
+ return collectionsStore.getCollection(junctionCollection.value) !== null;
+ });
+
+ const relatedCollectionExists = computed(() => {
+ return collectionsStore.getCollection(state.relations[1].one_collection) !== null;
+ });
+
const junctionFields = computed(() => {
if (!junctionCollection.value) return [];
@@ -117,7 +188,7 @@ export default defineComponent({
}));
});
- return { relations: state.relations, collectionItems, junctionCollection, junctionFields };
+ return { relations: state.relations, collectionItems, junctionCollection, junctionFields, junctionCollectionExists, relatedCollectionExists };
},
});
@@ -133,11 +204,12 @@ export default defineComponent({
gap: 20px;
margin-top: 48px;
- .v-icon {
+ .v-icon.arrow {
--v-icon-color: var(--foreground-subdued);
position: absolute;
transform: translateX(-50%);
+ pointer-events: none;
&:first-of-type {
bottom: 85px;
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 e8b357f83f..5db0dd1294 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
@@ -12,6 +12,7 @@ import { getInterfaces } from '@/interfaces';
import { getDisplays } from '@/displays';
import { InterfaceConfig } from '@/interfaces/types';
import { DisplayConfig } from '@/displays/types';
+import { Field } from '@/types';
const fieldsStore = useFieldsStore();
const relationsStore = useRelationsStore();
@@ -160,7 +161,7 @@ function initLocalStore(
has_auto_increment: true,
},
system: {
- interface: 'text-input',
+ hidden: true,
}
}
]
@@ -238,7 +239,7 @@ function initLocalStore(
has_auto_increment: true,
},
system: {
- interface: 'text-input',
+ hidden: true,
}
}
]
@@ -315,6 +316,69 @@ function initLocalStore(
delete state.fieldData.schema;
delete state.fieldData.type;
+ const syncNewCollectionsM2M = throttle((
+ [junctionCollection, manyCurrent, manyRelated, relatedCollection],
+ [oldJunctionCollection, oldManyCurrent, oldManyRelated, oldRelatedCollection]
+ ) => {
+ state.newCollections = state.newCollections.filter((col: any) => [junctionCollection, relatedCollection, oldJunctionCollection, oldRelatedCollection].includes(col.collection) === false);
+ state.newFields = state.newFields
+ .filter((field: Partial) => [manyCurrent, manyRelated, relatedCollection, oldManyCurrent, oldManyRelated, oldRelatedCollection].includes(field.field) === false);
+
+ if (collectionExists(junctionCollection) === false) {
+ state.newCollections.push({
+ collection: junctionCollection,
+ fields: [
+ {
+ field: 'id',
+ type: 'integer',
+ schema: {
+ has_auto_increment: true,
+ },
+ meta: {
+ hidden: true,
+ }
+ }
+ ]
+ });
+ }
+
+ if (fieldExists(junctionCollection, manyCurrent) === false) {
+ state.newFields.push({
+ collection: junctionCollection,
+ field: manyCurrent,
+ type: fieldsStore.getPrimaryKeyFieldForCollection(junctionCollection)?.type,
+ schema: {},
+ });
+ }
+
+ if (fieldExists(junctionCollection, manyRelated) === false) {
+ state.newFields.push({
+ collection: junctionCollection,
+ field: manyRelated,
+ type: collectionExists(relatedCollection) ? fieldsStore.getPrimaryKeyFieldForCollection(relatedCollection)?.type : 'integer',
+ schema: {},
+ });
+ }
+
+ if (collectionExists(relatedCollection) === false) {
+ state.newCollections.push({
+ collection: relatedCollection,
+ fields: [
+ {
+ field: state.relations[1].one_primary,
+ type: 'integer',
+ schema: {
+ has_auto_increment: true,
+ },
+ meta: {
+ hidden: true,
+ }
+ }
+ ]
+ })
+ }
+ }, 50);
+
if (!isExisting) {
state.fieldData.meta.special = 'm2m';
@@ -348,9 +412,11 @@ function initLocalStore(
watch(
() => state.relations[0].many_collection,
() => {
- const pkField = fieldsStore.getPrimaryKeyFieldForCollection(state.relations[0].many_collection)?.field;
- state.relations[0].many_primary = pkField;
- state.relations[1].many_primary = pkField;
+ if (collectionExists(state.relations[0].many_collection)) {
+ const pkField = fieldsStore.getPrimaryKeyFieldForCollection(state.relations[0].many_collection)?.field;
+ state.relations[0].many_primary = pkField;
+ state.relations[1].many_primary = pkField;
+ }
}
);
@@ -371,11 +437,23 @@ function initLocalStore(
watch(
() => state.relations[1].one_collection,
() => {
- state.relations[1].one_primary = fieldsStore.getPrimaryKeyFieldForCollection(
- state.relations[1].one_collection
- )?.field;
+ if (collectionExists(state.relations[1].one_collection)) {
+ state.relations[1].one_primary = fieldsStore.getPrimaryKeyFieldForCollection(
+ state.relations[1].one_collection
+ )?.field;
+ }
}
);
+
+ watch(
+ [
+ () => state.relations[0].many_collection,
+ () => state.relations[0].many_field,
+ () => state.relations[1].many_field,
+ () => state.relations[1].one_collection,
+ ],
+ syncNewCollectionsM2M
+ )
}
if (type === 'presentation') {
@@ -420,7 +498,7 @@ function initLocalStore(
}
function fieldExists(collection: string, field: string) {
- return fieldsStore.getField(collection, field) !== null;
+ return collectionExists(collection) && fieldsStore.getField(collection, field) !== null;
}
}