Interface grouping (#717)

* Manage types

* Fix typing

* Unset interface on local type change

* Add note

* Limit available displays based on localType

* Filter displays based on localtype

* Only show displays that fit the type

* Limit type options for interface selection

* Dont import unused type
This commit is contained in:
Rijk van Zanten
2020-06-12 16:51:12 -04:00
committed by GitHub
parent 4e8a7de004
commit 5a745b0c4d
15 changed files with 214 additions and 85 deletions

View File

@@ -325,7 +325,7 @@ export default defineComponent({
if (systemFields[2].enabled === true) {
fields.push({
type: 'owner',
type: 'user_created',
datatype: 'INT',
field: systemFields[2].name,
interface: 'owner',

View File

@@ -10,7 +10,8 @@
import { defineComponent, computed, PropType } from '@vue/composition-api';
import i18n from '@/lang';
import { FormField } from '@/components/v-form/types';
import { Field } from '@/stores/fields/types';
import { Field, types } from '@/stores/fields/types';
import interfaces from '@/interfaces';
export default defineComponent({
props: {
@@ -24,6 +25,21 @@ export default defineComponent({
},
},
setup(props) {
const selectedInterface = computed(() => interfaces.find((inter) => inter.id === props.value.interface));
const typeChoices = computed(() => {
let availableTypes = types;
if (selectedInterface.value) {
availableTypes = selectedInterface.value.types;
}
return availableTypes.map((type) => ({
text: i18n.t(type),
value: type,
}));
});
const fields = computed(() => {
const fields: FormField[] = [
{
@@ -127,8 +143,11 @@ export default defineComponent({
{
field: 'type',
name: i18n.t('directus_type'),
interface: 'text-input',
interface: 'dropdown',
width: 'half',
options: {
choices: typeChoices.value,
},
},
{
field: 'datatype',

View File

@@ -29,6 +29,8 @@ import { defineComponent, computed, PropType } from '@vue/composition-api';
import displays from '@/displays/';
import { FancySelectItem } from '@/components/v-fancy-select/types';
import { Field } from '@/stores/fields/types';
import { localTypeGroups } from './index';
import { LocalType } from './types';
export default defineComponent({
props: {
@@ -40,14 +42,30 @@ export default defineComponent({
type: Object as PropType<Field>,
required: true,
},
localType: {
type: String as PropType<LocalType>,
required: true,
},
},
setup(props, { emit }) {
const items = computed<FancySelectItem[]>(() => {
return displays.map((inter) => ({
text: inter.name,
value: inter.id,
icon: inter.icon,
}));
return (
displays
// Filter interfaces based on the localType that was selected
.filter((display) => {
return display.types.some((type) => localTypeGroups[props.localType].includes(type));
})
// When choosing an interface, the type is preset. We can safely assume that a
// type has been set when you reach the display pane
.filter((display) => {
return display.types.includes(props.value.type);
})
.map((inter) => ({
text: inter.name,
value: inter.id,
icon: inter.icon,
}))
);
});
const selectedDisplay = computed(() => {

View File

@@ -14,12 +14,7 @@
:disabled="isNew === false"
/>
<v-fancy-select
:disabled="isNew === false"
:items="items"
:value="localType"
@input="$emit('update:localType', $event)"
/>
<v-fancy-select :disabled="isNew === false" :items="items" :value="localType" @input="setLocalType" />
</div>
</template>
@@ -69,7 +64,7 @@ export default defineComponent({
},
]);
return { emitValue, items };
return { emitValue, items, setLocalType };
function emitValue(key: string, value: any) {
emit('input', {
@@ -77,6 +72,17 @@ export default defineComponent({
[key]: value,
});
}
function setLocalType(newType: string) {
emit('update:localType', newType);
// Reset the interface when changing the localtype. If you change localType, the previously
// selected interface most likely doesn't exist in the new selection anyways
emit('input', {
...props.value,
interface: null,
});
}
},
});
</script>

View File

@@ -2,7 +2,7 @@
<div>
<h2 class="type-title" v-if="isNew">{{ $t('interface_setup_title') }}</h2>
<v-fancy-select :items="items" :value="value.interface" @input="emitValue('interface', $event)" />
<v-fancy-select :items="items" :value="value.interface" @input="setInterface" />
<template v-if="selectedInterface">
<v-form
@@ -29,6 +29,8 @@ import { defineComponent, computed, PropType } from '@vue/composition-api';
import interfaces from '@/interfaces/';
import { FancySelectItem } from '@/components/v-fancy-select/types';
import { Field } from '@/stores/fields/types';
import { LocalType } from './types';
import { localTypeGroups } from './index';
export default defineComponent({
props: {
@@ -40,21 +42,59 @@ export default defineComponent({
type: Object as PropType<Field>,
required: true,
},
localType: {
type: String as PropType<LocalType>,
required: true,
},
},
setup(props, { emit }) {
const items = computed<FancySelectItem[]>(() => {
return interfaces.map((inter) => ({
text: inter.name,
value: inter.id,
icon: inter.icon,
}));
return (
interfaces
// Filter interfaces based on the localType that was selected
.filter((inter) => {
return inter.types.some((type) => localTypeGroups[props.localType].includes(type));
})
.filter((inter) => {
if (props.value.type && props.isNew === false) {
return inter.types.includes(props.value.type);
}
return true;
})
.map((inter) => ({
text: inter.name,
value: inter.id,
icon: inter.icon,
}))
);
});
const selectedInterface = computed(() => {
return interfaces.find((inter) => inter.id === props.value.interface) || null;
});
return { emitValue, items, selectedInterface };
return { emitValue, items, selectedInterface, setInterface };
function setInterface(value: string | null) {
if (value === null) {
return emit('input', {
...props.value,
interface: null,
});
}
const chosenInterface = interfaces.find((inter) => inter.id === value);
if (!chosenInterface) return;
// This also presets the field type
emit('input', {
...props.value,
interface: value,
type: chosenInterface.types[0],
});
}
function emitValue(key: string, value: any) {
emit('input', {

View File

@@ -74,8 +74,9 @@ import useFieldsStore from '@/stores/fields/';
import { Relation } from '@/stores/relations/types';
import api from '@/api';
import useProjectsStore from '@/stores/projects';
import { LocalType } from './types';
import { localTypeGroups } from './index';
import { Type } from '@/stores/fields/types';
export default defineComponent({
components: {
@@ -109,7 +110,7 @@ export default defineComponent({
const fieldsStore = useFieldsStore();
const projectsStore = useProjectsStore();
const { field, localType } = usefield();
const { field, localType } = useField();
const { tabs, currentTab } = useTabs();
const { save, saving } = useSave();
@@ -117,7 +118,7 @@ export default defineComponent({
return { field, tabs, currentTab, localType, save, saving, newRelations };
function usefield() {
function useField() {
const defaults = {
id: null,
collection: props.collection,
@@ -166,16 +167,13 @@ export default defineComponent({
if (existingField) {
field.value = existingField;
const type = existingField.type.toLowerCase();
const type: Type = existingField.type;
if (type === 'file') {
localType.value = 'file';
} else if (type === 'files') {
localType.value = 'files';
} else if (['o2m', 'm2o', 'm2m'].includes(type)) {
localType.value = 'relational';
} else {
localType.value = 'standard';
for (const [group, types] of Object.entries(localTypeGroups)) {
if (types.includes(type)) {
localType.value = group as LocalType;
break;
}
}
} else {
field.value = { ...defaults };

View File

@@ -1,4 +1,21 @@
import FieldSetup from './field-setup.vue';
import { types, Type } from '@/stores/fields/types';
import { LocalType } from './types';
const localTypeGroups: Record<LocalType, Type[]> = {
relational: ['m2o', 'o2m', 'm2m', 'translation'],
file: ['file'],
files: ['files'],
standard: [],
};
localTypeGroups.standard = types.filter((typeName: Type) => {
return (
[...localTypeGroups.relational, ...localTypeGroups.file, ...localTypeGroups.files].includes(typeName) === false
);
});
export { localTypeGroups };
export { FieldSetup };
export default FieldSetup;

View File

@@ -13,7 +13,7 @@
/>
<permissions-toggle
type="read"
:options="ownerField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:options="userCreatedField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:value="getCombinedPermission('read')"
:save-permission="saveForAllStatuses"
:collection="collection"
@@ -21,7 +21,7 @@
/>
<permissions-toggle
type="update"
:options="ownerField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:options="userCreatedField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:value="getCombinedPermission('update')"
:save-permission="saveForAllStatuses"
:collection="collection"
@@ -29,7 +29,7 @@
/>
<permissions-toggle
type="delete"
:options="ownerField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:options="userCreatedField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:value="getCombinedPermission('delete')"
:save-permission="saveForAllStatuses"
:collection="collection"
@@ -117,7 +117,7 @@
/>
<permissions-toggle
type="read"
:options="ownerField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:options="userCreatedField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:value="getPermissionValue('read', status.value)"
:status="status.value"
:save-permission="savePermission"
@@ -127,7 +127,7 @@
/>
<permissions-toggle
type="update"
:options="ownerField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:options="userCreatedField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:value="getPermissionValue('update', status.value)"
:status="status.value"
:save-permission="savePermission"
@@ -137,7 +137,7 @@
/>
<permissions-toggle
type="delete"
:options="ownerField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:options="userCreatedField ? ['none', 'mine', 'role', 'full'] : ['none', 'full']"
:value="getPermissionValue('delete', status.value)"
:status="status.value"
:save-permission="savePermission"
@@ -241,7 +241,7 @@ export default defineComponent({
},
setup(props) {
const { collection } = toRefs(props);
const { fields, info, statusField, ownerField } = useCollection(collection);
const { fields, info, statusField, userCreatedField } = useCollection(collection);
const detailsOpen = ref(false);
@@ -289,7 +289,7 @@ export default defineComponent({
statuses,
detailsOpen,
permissions,
ownerField,
userCreatedField,
getPermissionValue,
getCombinedPermission,
saveForAllStatuses,