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:
Azri Kahar
2022-10-15 09:56:03 +08:00
committed by GitHub
parent dc7c62f0ef
commit bb51d5a618
6 changed files with 160 additions and 9 deletions

View File

@@ -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,

View File

@@ -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!;

View File

@@ -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');
}

View File

@@ -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);

View File

@@ -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 =

View File

@@ -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');
});
});
});