mirror of
https://github.com/directus/directus.git
synced 2026-04-03 03:00:39 -04:00
Reset junction collection/fields for field relationships with junction table (#15904)
* use `localType` to disable related collection in m2m this is because `localType` dictates the relationship type (eg. m2m, files), but `type` was only field type (eg. alias, string) * reset files junction when re-enabling auto fill * prevent m2m clearing related collection When re-enabled auto-fill, the updates only contain the autofill, not the m2o related collection value, so it was unintentionally resetting the value even when we are only toggling autofill * fix autofill for translations * fix m2a junction autofill toggles * use getCurrent instead of state * basic test for fieldDetailStore Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
|
||||
<div class="field">
|
||||
<div class="type-label">{{ t('related_collection') }}</div>
|
||||
<related-collection-select v-model="relatedCollection" :disabled="type === 'files' || isExisting" />
|
||||
<related-collection-select v-model="relatedCollection" :disabled="localType === 'files' || isExisting" />
|
||||
</div>
|
||||
|
||||
<v-input disabled :model-value="currentPrimaryKey" />
|
||||
@@ -216,7 +216,7 @@ export default defineComponent({
|
||||
const relationsStore = useRelationsStore();
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const { field, collection, editing, generationInfo } = storeToRefs(fieldDetailStore);
|
||||
const { collection, editing, generationInfo, localType } = storeToRefs(fieldDetailStore);
|
||||
|
||||
const sortField = syncFieldDetailStoreProperty('relations.o2m.meta.sort_field');
|
||||
const junctionCollection = syncFieldDetailStoreProperty('relations.o2m.collection');
|
||||
@@ -230,7 +230,6 @@ export default defineComponent({
|
||||
const correspondingField = syncFieldDetailStoreProperty('fields.corresponding');
|
||||
const correspondingFieldKey = syncFieldDetailStoreProperty('fields.corresponding.field');
|
||||
|
||||
const type = computed(() => field.value.type);
|
||||
const isExisting = computed(() => editing.value !== '+');
|
||||
|
||||
const currentPrimaryKey = computed(() => fieldsStore.getPrimaryKeyFieldForCollection(collection.value!)?.field);
|
||||
@@ -281,7 +280,7 @@ export default defineComponent({
|
||||
t,
|
||||
autoGenerateJunctionRelation,
|
||||
collection,
|
||||
type,
|
||||
localType,
|
||||
isExisting,
|
||||
junctionCollection,
|
||||
junctionFieldCurrent,
|
||||
|
||||
@@ -10,7 +10,11 @@ export function applyChanges(updates: StateUpdates, state: State, helperFn: Help
|
||||
removeSchema(updates);
|
||||
setTypeToAlias(updates);
|
||||
prepareRelation(updates, state);
|
||||
setDefaults(updates, state);
|
||||
setDefaults(updates, state, helperFn);
|
||||
}
|
||||
|
||||
if (hasChanged('autoGenerateJunctionRelation')) {
|
||||
setDefaults(updates, state, helperFn);
|
||||
}
|
||||
|
||||
if (hasChanged('field.field')) {
|
||||
@@ -203,7 +207,9 @@ function generateFields(updates: StateUpdates, state: State, { getCurrent }: Hel
|
||||
}
|
||||
}
|
||||
|
||||
export function setDefaults(updates: StateUpdates, state: State) {
|
||||
export function setDefaults(updates: StateUpdates, state: State, { getCurrent }: HelperFunctions) {
|
||||
if (getCurrent('autoGenerateJunctionRelation') === false) return;
|
||||
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const currentCollection = state.collection!;
|
||||
|
||||
@@ -13,6 +13,10 @@ export function applyChanges(updates: StateUpdates, state: State, helperFn: Help
|
||||
setDefaults(updates, state, helperFn);
|
||||
}
|
||||
|
||||
if (hasChanged('autoGenerateJunctionRelation')) {
|
||||
setDefaults(updates, state, helperFn);
|
||||
}
|
||||
|
||||
if (hasChanged('field.field')) {
|
||||
updateRelationField(updates);
|
||||
autoGenerateJunctionCollectionName(updates, state, helperFn);
|
||||
@@ -87,6 +91,8 @@ export function prepareRelation(updates: StateUpdates, state: State) {
|
||||
}
|
||||
|
||||
export function setDefaults(updates: StateUpdates, state: State, { getCurrent }: HelperFunctions) {
|
||||
if (getCurrent('autoGenerateJunctionRelation') === false) return;
|
||||
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const currentCollection = state.collection!;
|
||||
@@ -99,7 +105,11 @@ export function setDefaults(updates: StateUpdates, state: State, { getCurrent }:
|
||||
set(updates, 'relations.o2m.field', `${currentCollection}_${currentCollectionPrimaryKeyField}`);
|
||||
set(updates, 'relations.m2o.collection', junctionName);
|
||||
set(updates, 'relations.m2o.field', 'item');
|
||||
set(updates, 'relations.m2o.meta.one_allowed_collections', []);
|
||||
set(
|
||||
updates,
|
||||
'relations.m2o.meta.one_allowed_collections',
|
||||
getCurrent('relations.m2o.meta.one_allowed_collections') ?? []
|
||||
);
|
||||
set(updates, 'relations.m2o.meta.one_collection_field', 'collection');
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,8 @@ export function autoGenerateJunctionFields(updates: StateUpdates, state: State,
|
||||
|
||||
const currentCollection = state.collection!;
|
||||
const currentPrimaryKeyField = fieldsStore.getPrimaryKeyFieldForCollection(currentCollection)?.field ?? 'id';
|
||||
const relatedCollection = updates.relations?.m2o?.related_collection;
|
||||
const relatedCollection =
|
||||
updates.relations?.m2o?.related_collection ?? getCurrent('relations.m2o.related_collection');
|
||||
|
||||
if (relatedCollection) {
|
||||
const automaticJunctionCollectionName = getAutomaticJunctionCollectionName(currentCollection, relatedCollection);
|
||||
|
||||
@@ -13,6 +13,10 @@ export function applyChanges(updates: StateUpdates, state: State, helperFn: Help
|
||||
setDefaults(updates, state, helperFn);
|
||||
}
|
||||
|
||||
if (hasChanged('autoGenerateJunctionRelation')) {
|
||||
setDefaults(updates, state, helperFn);
|
||||
}
|
||||
|
||||
if (hasChanged('field.field')) {
|
||||
updateRelationField(updates);
|
||||
}
|
||||
@@ -332,6 +336,8 @@ function generateFields(updates: StateUpdates, state: State, { getCurrent }: Hel
|
||||
}
|
||||
|
||||
export function setDefaults(updates: StateUpdates, state: State, { getCurrent }: HelperFunctions) {
|
||||
if (getCurrent('autoGenerateJunctionRelation') === false) return;
|
||||
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const currentCollection = state.collection!;
|
||||
@@ -343,7 +349,7 @@ export function setDefaults(updates: StateUpdates, state: State, { getCurrent }:
|
||||
set(updates, 'relations.o2m.collection', junctionName);
|
||||
set(updates, 'relations.o2m.field', `${currentCollection}_${currentCollectionPrimaryKeyField}`);
|
||||
set(updates, 'relations.m2o.collection', junctionName);
|
||||
set(updates, 'relations.m2o.related_collection', 'languages');
|
||||
set(updates, 'relations.m2o.related_collection', getCurrent('relations.m2o.related_collection') ?? 'languages');
|
||||
|
||||
const languagesCollection = getCurrent('relations.m2o.related_collection');
|
||||
const languagesCollectionPrimaryKeyField =
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { setActivePinia } from 'pinia';
|
||||
import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
|
||||
|
||||
import { cryptoStub } from '@/__utils__/crypto';
|
||||
vi.stubGlobal('crypto', cryptoStub);
|
||||
|
||||
import { useFieldsStore } from '@/stores/fields';
|
||||
import { useRelationsStore } from '@/stores/relations';
|
||||
import { useFieldDetailStore } from './index';
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(
|
||||
createTestingPinia({
|
||||
createSpy: vi.fn,
|
||||
stubActions: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('Actions', () => {
|
||||
describe('startEditing', () => {
|
||||
it('New Field', () => {
|
||||
const fieldDetailStore = useFieldDetailStore();
|
||||
const testValue: { collection: string; field: string; localType: 'presentation' } = {
|
||||
collection: 'collection_a',
|
||||
field: '+',
|
||||
localType: 'presentation',
|
||||
};
|
||||
fieldDetailStore.startEditing(testValue.collection, testValue.field, testValue.localType);
|
||||
expect(fieldDetailStore.collection).toEqual(testValue.collection);
|
||||
expect(fieldDetailStore.field.collection).toEqual(testValue.collection);
|
||||
expect(fieldDetailStore.editing).toEqual(testValue.field);
|
||||
expect(fieldDetailStore.localType).toEqual(testValue.localType);
|
||||
});
|
||||
it('Existing Field — M2O', () => {
|
||||
const mockedField = {
|
||||
collection: 'collection_a',
|
||||
field: 'collection_a_field',
|
||||
type: 'alias',
|
||||
meta: {
|
||||
collection: 'collection_a',
|
||||
field: 'collection_a_field',
|
||||
},
|
||||
name: 'Collection A Field',
|
||||
};
|
||||
const fieldsStore = useFieldsStore();
|
||||
(fieldsStore.getField as Mock).mockReturnValue(mockedField);
|
||||
|
||||
const mockedRelations = [
|
||||
{
|
||||
collection: 'collection_a',
|
||||
field: 'collection_a_field',
|
||||
related_collection: 'collection_b',
|
||||
meta: {
|
||||
many_collection: 'collection_a',
|
||||
many_field: 'collection_a_field',
|
||||
one_collection: 'collection_b',
|
||||
one_field: null,
|
||||
one_collection_field: null,
|
||||
one_allowed_collections: null,
|
||||
junction_field: null,
|
||||
sort_field: null,
|
||||
one_deselect_action: 'nullify',
|
||||
},
|
||||
},
|
||||
];
|
||||
const relationsStore = useRelationsStore();
|
||||
(relationsStore.getRelationsForField as Mock).mockReturnValue(mockedRelations);
|
||||
|
||||
const fieldDetailStore = useFieldDetailStore();
|
||||
fieldDetailStore.startEditing(mockedField.collection, mockedField.field);
|
||||
expect(fieldDetailStore.collection).toEqual(mockedField.collection);
|
||||
expect(fieldDetailStore.field.collection).toEqual(mockedField.collection);
|
||||
expect(fieldDetailStore.editing).toEqual(mockedField.field);
|
||||
expect(fieldDetailStore.field.name).toEqual(mockedField.name);
|
||||
expect(fieldDetailStore.localType).toEqual('m2o');
|
||||
expect(fieldDetailStore.relations.o2m).toEqual(undefined);
|
||||
expect(fieldDetailStore.relations.m2o).toEqual(
|
||||
mockedRelations.find(
|
||||
(relation) => relation.collection === mockedField.collection && relation.field === mockedField.field
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
it.todo('Existing Field — M2M');
|
||||
});
|
||||
|
||||
describe('Alterations', () => {
|
||||
describe('files', () => {
|
||||
it('autoGenerateJunctionRelation has changed', () => {
|
||||
const fieldDetailStore = useFieldDetailStore();
|
||||
const testValue: { collection: string; field: string; localType: 'files' } = {
|
||||
collection: 'collection_a',
|
||||
field: '+',
|
||||
localType: 'files',
|
||||
};
|
||||
fieldDetailStore.startEditing(testValue.collection, testValue.field, testValue.localType);
|
||||
|
||||
const fieldsStore = useFieldsStore();
|
||||
(fieldsStore.getPrimaryKeyFieldForCollection as Mock).mockReturnValue({
|
||||
collection: 'collection_a',
|
||||
field: 'id',
|
||||
});
|
||||
expect(fieldDetailStore.collection).toEqual(testValue.collection);
|
||||
expect(fieldDetailStore.field.collection).toEqual(testValue.collection);
|
||||
expect(fieldDetailStore.editing).toEqual(testValue.field);
|
||||
expect(fieldDetailStore.relations.o2m?.collection).toEqual('collection_a_files');
|
||||
expect(fieldDetailStore.relations.o2m?.field).toEqual('collection_a_id');
|
||||
expect(fieldDetailStore.relations.m2o?.related_collection).toEqual('directus_files');
|
||||
expect(fieldDetailStore.relations.m2o?.field).toEqual('directus_files_id');
|
||||
|
||||
fieldDetailStore.update({ autoGenerateJunctionRelation: false });
|
||||
fieldDetailStore.update({
|
||||
relations: {
|
||||
o2m: {
|
||||
collection: 'custom_files',
|
||||
},
|
||||
},
|
||||
});
|
||||
fieldDetailStore.update({ autoGenerateJunctionRelation: true });
|
||||
|
||||
expect(fieldDetailStore.relations.o2m?.collection).toEqual('collection_a_files');
|
||||
expect(fieldDetailStore.relations.o2m?.field).toEqual('collection_a_id');
|
||||
expect(fieldDetailStore.relations.m2o?.related_collection).toEqual('directus_files');
|
||||
expect(fieldDetailStore.relations.m2o?.field).toEqual('directus_files_id');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user