Show translations as group on field management

This commit is contained in:
rijkvanzanten
2020-09-25 16:58:40 -04:00
parent 5b76b9707f
commit 0f797217f5
8 changed files with 180 additions and 64 deletions

View File

@@ -164,7 +164,9 @@ body {
}
&.disabled {
--v-list-item-color: var(--foreground-subdued);
--v-list-item-color: var(--foreground-subdued) !important;
cursor: not-allowed;
}
@at-root {

View File

@@ -200,6 +200,8 @@
"click_here": "Click here",
"to_manually_setup_translations": "to manually setup translations.",
"click_to_manage_translated_fields": "There are no translated fields yet. Click here to create them. | There is one translated field. Click here to manage it. | There are {count} translated fields. Click here to manage them.",
"configure_m2o": "Configure your Many-to-One Relationship...",
"configure_o2m": "Configure your One-to-Many Relationship...",
"configure_m2m": "Configure your Many-to-Many Relationship...",

View File

@@ -1,5 +1,9 @@
<template>
<v-dialog persistent :active="true" v-if="localType === 'translations' && translationsManual === false">
<v-dialog
persistent
:active="true"
v-if="localType === 'translations' && translationsManual === false && field === '+'"
>
<v-card class="auto-translations">
<v-card-title>{{ $t('create_translations') }}</v-card-title>
<v-card-text>
@@ -105,6 +109,7 @@ import { Field } from '@/types';
import router from '@/router';
import useCollection from '@/composables/use-collection';
import notify from '@/utils/notify';
import { getLocalTypeForField } from '../get-local-type';
import { initLocalStore, state, clearLocalStore } from './store';
@@ -351,58 +356,16 @@ export default defineComponent({
router.push(`/settings/data-model/${props.collection}`);
clearLocalStore();
}
function getLocalTypeForField(
collection: string,
field: string
): 'standard' | 'file' | 'files' | 'o2m' | 'm2m' | 'm2o' | 'presentation' | 'translations' {
const fieldInfo = fieldsStore.getField(collection, field);
const relations = relationsStore.getRelationsForField(collection, field);
if (relations.length === 0) {
if (fieldInfo.type === 'alias') return 'presentation';
return 'standard';
}
if (relations.length === 1) {
const relation = relations[0];
if (relation.one_collection === 'directus_files') return 'file';
if (relation.many_collection === collection) return 'm2o';
return 'o2m';
}
if (relations.length === 2) {
if ((fieldInfo.meta?.special || []).includes('translations')) {
return 'translations';
}
const relationForCurrent = relations.find(
(relation: Relation) =>
(relation.many_collection === collection && relation.many_field === field) ||
(relation.one_collection === collection && relation.one_field === field)
);
if (relationForCurrent?.many_collection === collection && relationForCurrent?.many_field === field)
return 'm2o';
if (
relations[0].one_collection === 'directus_files' ||
relations[1].one_collection === 'directus_files'
) {
return 'files';
} else {
return 'm2m';
}
}
return 'standard';
}
},
});
</script>
<style lang="scss" scoped>
.auto-translations {
.v-input {
--v-input-font-family: var(--family-monospace);
}
.v-notice {
margin-top: 12px;
}

View File

@@ -508,6 +508,10 @@ function initLocalStore(
one_primary: type === 'files' ? 'id' : '',
},
];
if (type === 'translations') {
state.fieldData.field = 'translations';
}
}
watch(

View File

@@ -1,6 +1,46 @@
<template>
<div :class="(field.meta && field.meta.width) || 'full'">
<v-menu attached>
<div v-if="localType === 'translations'" class="group">
<div class="header">
<v-icon class="drag-handle" name="drag_indicator" />
<v-menu show-arrow>
<template #activator="{ toggle }">
<span class="group-options" @click="toggle">
<span class="name" v-tooltip="field.field">{{ field.name }}</span>
<v-icon name="expand_more" />
</span>
</template>
<v-list dense>
<v-list-item :to="`/settings/data-model/${field.collection}/${field.field}`">
<v-list-item-icon><v-icon name="edit" outline /></v-list-item-icon>
<v-list-item-content>
{{ $t('edit_field') }}
</v-list-item-content>
</v-list-item>
<v-divider />
<v-list-item @click="deleteActive = true" class="danger">
<v-list-item-icon><v-icon name="delete" outline /></v-list-item-icon>
<v-list-item-content>
{{ $t('delete_field') }}
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
</div>
<router-link :to="`/settings/data-model/${translationsCollection}`">
<v-notice type="info" icon="translate">
<div>{{ $tc('click_to_manage_translated_fields', translationsFieldsCount) }}</div>
<div class="spacer" />
<v-icon name="launch" />
</v-notice>
</router-link>
</div>
<v-menu v-else attached>
<template #activator="{ toggle, active }">
<v-input class="field" :class="{ hidden, active }" readonly @click="openFieldDetail">
<template #prepend>
@@ -140,12 +180,13 @@
<script lang="ts">
import { defineComponent, PropType, ref, computed } from '@vue/composition-api';
import { Field } from '@/types';
import { useCollectionsStore, useFieldsStore } from '@/stores/';
import { Field, Relation } from '@/types';
import { useCollectionsStore, useFieldsStore, useRelationsStore } from '@/stores/';
import { getInterfaces } from '@/interfaces';
import router from '@/router';
import notify from '@/utils/notify';
import { i18n } from '@/lang';
import { getLocalTypeForField } from '../../get-local-type';
export default defineComponent({
props: {
@@ -155,11 +196,12 @@ export default defineComponent({
},
},
setup(props) {
const relationsStore = useRelationsStore();
const collectionsStore = useCollectionsStore();
const fieldsStore = useFieldsStore();
const interfaces = getInterfaces();
const editActive = ref(false);
const fieldsStore = useFieldsStore();
const collectionsStore = useCollectionsStore();
const { deleteActive, deleting, deleteField } = useDeleteField();
const { duplicateActive, duplicateName, collections, duplicateTo, saveDuplicate, duplicating } = useDuplicate();
@@ -170,6 +212,10 @@ export default defineComponent({
const hidden = computed(() => props.field.meta?.hidden === true);
const localType = computed(() => getLocalTypeForField(props.field.collection, props.field.field));
const { translationsCollection, translationsFieldsCount } = useTranslations();
return {
interfaceName,
editActive,
@@ -186,6 +232,9 @@ export default defineComponent({
openFieldDetail,
hidden,
toggleVisibility,
localType,
translationsCollection,
translationsFieldsCount,
};
function setWidth(width: string) {
@@ -275,6 +324,30 @@ export default defineComponent({
router.push(`/settings/data-model/${props.field.collection}/${props.field.field}`);
}
function useTranslations() {
const translationsCollection = computed(() => {
if (localType.value !== 'translations') return null;
const relation = relationsStore.state.relations.find((relation: Relation) => {
return (
relation.one_collection === props.field.collection && relation.one_field === props.field.field
);
});
if (!relation) return null;
return relation.many_collection;
});
const translationsFieldsCount = computed(() => {
const fields = fieldsStore.getFieldsForCollection(translationsCollection.value);
return fields.filter((field: Field) => field.meta?.hidden !== true).length;
});
return { translationsCollection, translationsFieldsCount };
}
},
});
</script>
@@ -282,11 +355,6 @@ export default defineComponent({
<style lang="scss" scoped>
@import '@/styles/mixins/breakpoint';
// The default display: contents doens't play nicely with drag and drop
.v-menu {
display: block;
}
.full,
.fill {
grid-column: 1 / span 2;
@@ -373,4 +441,36 @@ export default defineComponent({
margin-left: 8px;
}
}
.spacer {
flex-grow: 1;
}
.group {
position: relative;
top: -8px;
left: -8px;
width: calc(100% + 16px);
height: calc(100% + 16px);
margin: 8px 0;
padding: 8px;
background-color: var(--background-subdued);
border-radius: var(--border-radius);
.header {
margin-bottom: 8px;
}
.drag-handle {
margin-right: 4px;
}
.group-options {
cursor: pointer;
}
.v-notice {
cursor: pointer;
}
}
</style>

View File

@@ -137,8 +137,8 @@ export default defineComponent({
{
type: 'translations',
icon: 'translate',
text: i18n.t('translations')
}
text: i18n.t('translations'),
},
]);
return {
@@ -169,9 +169,6 @@ export default defineComponent({
.fields-management {
margin-bottom: 24px;
padding: 12px;
background-color: var(--background-subdued);
border-radius: var(--border-radius);
}
.field-grid {

View File

@@ -2,7 +2,7 @@
<private-view :title="collectionInfo && collectionInfo.name">
<template #headline>{{ $t('settings_data_model') }}</template>
<template #title-outer:prepend>
<v-button class="header-icon" rounded icon exact to="/settings/data-model">
<v-button class="header-icon" rounded icon exact @click="$router.go(-1)">
<v-icon name="arrow_back" />
</v-button>
</template>

View File

@@ -0,0 +1,48 @@
import { useFieldsStore, useRelationsStore } from '@/stores';
import { Relation } from '@/types';
export function getLocalTypeForField(
collection: string,
field: string
): 'standard' | 'file' | 'files' | 'o2m' | 'm2m' | 'm2o' | 'presentation' | 'translations' {
const fieldsStore = useFieldsStore();
const relationsStore = useRelationsStore();
const fieldInfo = fieldsStore.getField(collection, field);
const relations = relationsStore.getRelationsForField(collection, field);
if (relations.length === 0) {
if (fieldInfo.type === 'alias') return 'presentation';
return 'standard';
}
if (relations.length === 1) {
const relation = relations[0];
if (relation.one_collection === 'directus_files') return 'file';
if (relation.many_collection === collection) return 'm2o';
return 'o2m';
}
if (relations.length === 2) {
if ((fieldInfo.meta?.special || []).includes('translations')) {
return 'translations';
}
const relationForCurrent = relations.find(
(relation: Relation) =>
(relation.many_collection === collection && relation.many_field === field) ||
(relation.one_collection === collection && relation.one_field === field)
);
if (relationForCurrent?.many_collection === collection && relationForCurrent?.many_field === field)
return 'm2o';
if (relations[0].one_collection === 'directus_files' || relations[1].one_collection === 'directus_files') {
return 'files';
} else {
return 'm2m';
}
}
return 'standard';
}