diff --git a/app/src/interfaces/list-m2m/use-relation.ts b/app/src/composables/use-m2m.ts similarity index 86% rename from app/src/interfaces/list-m2m/use-relation.ts rename to app/src/composables/use-m2m.ts index 6b791d7480..9ab8b8b338 100644 --- a/app/src/interfaces/list-m2m/use-relation.ts +++ b/app/src/composables/use-m2m.ts @@ -20,6 +20,8 @@ type UsableRelation = { relationInfo: ComputedRef; junctionPrimaryKeyField: ComputedRef; relationPrimaryKeyField: ComputedRef; + junctionFields: ComputedRef; + relationFields: ComputedRef; }; export default function useRelation(collection: Ref, field: Ref): UsableRelation { @@ -53,8 +55,12 @@ export default function useRelation(collection: Ref, field: Ref) return collectionsStore.getCollection(relation.value.related_collection!)!; }); - const { primaryKeyField: junctionPrimaryKeyField } = useCollection(junctionCollection.value.collection); - const { primaryKeyField: relationPrimaryKeyField } = useCollection(relationCollection.value.collection); + const { primaryKeyField: junctionPrimaryKeyField, fields: junctionFields } = useCollection( + junctionCollection.value.collection + ); + const { primaryKeyField: relationPrimaryKeyField, fields: relationFields } = useCollection( + relationCollection.value.collection + ); const relationInfo = computed(() => { return { @@ -75,5 +81,7 @@ export default function useRelation(collection: Ref, field: Ref) relationInfo, junctionPrimaryKeyField, relationPrimaryKeyField, + junctionFields, + relationFields, }; } diff --git a/app/src/displays/translations/index.ts b/app/src/displays/translations/index.ts new file mode 100644 index 0000000000..45afe6adb3 --- /dev/null +++ b/app/src/displays/translations/index.ts @@ -0,0 +1,59 @@ +import { defineDisplay } from '@directus/shared/utils'; +import adjustFieldsForDisplays from '@/utils/adjust-fields-for-displays'; +import { getFieldsFromTemplate } from '@directus/shared/utils'; +import options from './options.vue'; +import DisplayTranslations from './translations.vue'; +import { useFieldsStore, useRelationsStore } from '@/stores'; + +type Options = { + template: string; + languageField: string; +}; + +export default defineDisplay({ + id: 'translations', + name: '$t:displays.translations.translations', + description: '$t:displays.translations.description', + icon: 'translate', + component: DisplayTranslations, + options: options, + types: ['alias', 'string', 'uuid', 'integer', 'bigInteger', 'json'], + groups: ['m2m'], + fields: (options: Options | null, { field, collection }) => { + const fieldsStore = useFieldsStore(); + const relationsStore = useRelationsStore(); + const relations = relationsStore.getRelationsForField(collection, field); + + const translationsRelation = relations.find( + (relation) => relation.related_collection === collection && relation.meta?.one_field === field + ); + + const languagesRelation = relations.find((relation) => relation !== translationsRelation); + + const translationCollection = translationsRelation?.related_collection; + const languagesCollection = languagesRelation?.related_collection; + + if (!translationCollection || !languagesCollection) return []; + + const translationsPrimaryKeyField = fieldsStore.getPrimaryKeyFieldForCollection(translationCollection); + const languagesPrimaryKeyField = fieldsStore.getPrimaryKeyFieldForCollection(languagesCollection); + + const fields = options?.template + ? adjustFieldsForDisplays(getFieldsFromTemplate(options.template), translationCollection) + : []; + + if (translationsPrimaryKeyField && !fields.includes(translationsPrimaryKeyField.field)) { + fields.push(translationsPrimaryKeyField.field); + } + + if (languagesRelation?.field && !fields.includes(languagesRelation.field)) { + fields.push(`${languagesRelation.field}.${languagesPrimaryKeyField.field}`); + + if (options?.languageField) { + fields.push(`${languagesRelation.field}.${options.languageField}`); + } + } + + return fields; + }, +}); diff --git a/app/src/displays/translations/options.vue b/app/src/displays/translations/options.vue new file mode 100644 index 0000000000..51ffd977d1 --- /dev/null +++ b/app/src/displays/translations/options.vue @@ -0,0 +1,150 @@ + + + diff --git a/app/src/displays/translations/translations.vue b/app/src/displays/translations/translations.vue new file mode 100644 index 0000000000..88ffa3df0a --- /dev/null +++ b/app/src/displays/translations/translations.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/app/src/interfaces/files/files.vue b/app/src/interfaces/files/files.vue index 152ff12eb1..b4600c22d3 100644 --- a/app/src/interfaces/files/files.vue +++ b/app/src/interfaces/files/files.vue @@ -108,7 +108,7 @@ import { get } from 'lodash'; import Draggable from 'vuedraggable'; import useActions from '../list-m2m/use-actions'; -import useRelation from '../list-m2m/use-relation'; +import useRelation from '@/composables/use-m2m'; import usePreview from '../list-m2m/use-preview'; import useEdit from '../list-m2m/use-edit'; import useSelection from '../list-m2m/use-selection'; diff --git a/app/src/interfaces/list-m2m/list-m2m.vue b/app/src/interfaces/list-m2m/list-m2m.vue index e557c6e174..a0d78aa889 100644 --- a/app/src/interfaces/list-m2m/list-m2m.vue +++ b/app/src/interfaces/list-m2m/list-m2m.vue @@ -85,7 +85,7 @@ import { get } from 'lodash'; import Draggable from 'vuedraggable'; import useActions from './use-actions'; -import useRelation from './use-relation'; +import useRelation from '@/composables/use-m2m'; import usePreview from './use-preview'; import useEdit from './use-edit'; import usePermissions from './use-permissions'; diff --git a/app/src/interfaces/list-m2m/use-actions.ts b/app/src/interfaces/list-m2m/use-actions.ts index 5483ebd004..d620087dd0 100644 --- a/app/src/interfaces/list-m2m/use-actions.ts +++ b/app/src/interfaces/list-m2m/use-actions.ts @@ -1,6 +1,6 @@ import { get, has, isEqual } from 'lodash'; import { Ref } from 'vue'; -import { RelationInfo } from './use-relation'; +import { RelationInfo } from '@/composables/use-m2m'; type UsableActions = { getJunctionItem: (id: string | number) => string | number | Record | null; diff --git a/app/src/interfaces/list-m2m/use-edit.ts b/app/src/interfaces/list-m2m/use-edit.ts index ec3cf1c4bc..92cdab0b34 100644 --- a/app/src/interfaces/list-m2m/use-edit.ts +++ b/app/src/interfaces/list-m2m/use-edit.ts @@ -1,6 +1,6 @@ import { Ref, ref } from 'vue'; import { get, isEqual } from 'lodash'; -import { RelationInfo } from './use-relation'; +import { RelationInfo } from '@/composables/use-m2m'; type UsableEdit = { currentlyEditing: Ref; diff --git a/app/src/interfaces/list-m2m/use-preview.ts b/app/src/interfaces/list-m2m/use-preview.ts index 04ff5b0a09..83adfbba3c 100644 --- a/app/src/interfaces/list-m2m/use-preview.ts +++ b/app/src/interfaces/list-m2m/use-preview.ts @@ -5,7 +5,7 @@ import { Field } from '@directus/shared/types'; import { addRelatedPrimaryKeyToFields } from '@/utils/add-related-primary-key-to-fields'; import { cloneDeep, get, merge } from 'lodash'; import { Ref, ref, watch } from 'vue'; -import { RelationInfo } from './use-relation'; +import { RelationInfo } from '@/composables/use-m2m'; import { getEndpoint } from '@/utils/get-endpoint'; type UsablePreview = { diff --git a/app/src/interfaces/list-m2m/use-selection.ts b/app/src/interfaces/list-m2m/use-selection.ts index 7b71acf12c..9830dec56c 100644 --- a/app/src/interfaces/list-m2m/use-selection.ts +++ b/app/src/interfaces/list-m2m/use-selection.ts @@ -1,6 +1,6 @@ import { get } from 'lodash'; import { computed, ComputedRef, Ref, ref } from 'vue'; -import { RelationInfo } from './use-relation'; +import { RelationInfo } from '@/composables/use-m2m'; type UsableSelection = { stageSelection: (newSelection: (number | string)[]) => void; diff --git a/app/src/interfaces/list-m2m/use-sort.ts b/app/src/interfaces/list-m2m/use-sort.ts index 37c1efb032..556d2a79fc 100644 --- a/app/src/interfaces/list-m2m/use-sort.ts +++ b/app/src/interfaces/list-m2m/use-sort.ts @@ -1,7 +1,7 @@ import { Sort } from '@/components/v-table/types'; import { sortBy } from 'lodash'; import { computed, ComputedRef, Ref, ref } from 'vue'; -import { RelationInfo } from './use-relation'; +import { RelationInfo } from '@/composables/use-m2m'; type UsableSort = { sort: Ref; diff --git a/app/src/interfaces/translations/options.vue b/app/src/interfaces/translations/options.vue index 1785bfc79d..c19bc432b1 100644 --- a/app/src/interfaces/translations/options.vue +++ b/app/src/interfaces/translations/options.vue @@ -13,8 +13,8 @@