mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Fix ability to change M2O field type and prevent incompatible interfaces in advanced mode (#10096)
* Fix ability to change M2O field type and prevent incompatible interfaces in advanced mode * Removed unused imports * Rename interface variable
This commit is contained in:
@@ -15,11 +15,10 @@
|
||||
<script lang="ts">
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { getDisplays } from '@/displays';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { getDisplay } from '@/displays';
|
||||
import { getInterface } from '@/interfaces';
|
||||
import { FancySelectItem } from '@/components/v-fancy-select/types';
|
||||
import { clone } from 'lodash';
|
||||
import { InterfaceConfig, DisplayConfig } from '@directus/shared/types';
|
||||
import { useFieldDetailStore, syncFieldDetailStoreProperty } from '../store';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import ExtensionOptions from '../shared/extension-options.vue';
|
||||
@@ -36,12 +35,7 @@ export default defineComponent({
|
||||
const interfaceID = computed(() => field.value.meta?.interface);
|
||||
const display = syncFieldDetailStoreProperty('field.meta.display');
|
||||
|
||||
const { displays } = getDisplays();
|
||||
const { interfaces } = getInterfaces();
|
||||
|
||||
const selectedInterface = computed(() => {
|
||||
return interfaces.value.find((inter: InterfaceConfig) => inter.id === interfaceID.value);
|
||||
});
|
||||
const selectedInterface = computed(() => getInterface(interfaceID.value));
|
||||
|
||||
const selectItems = computed(() => {
|
||||
let recommended = clone(selectedInterface.value?.recommendedDisplays) || [];
|
||||
@@ -83,9 +77,7 @@ export default defineComponent({
|
||||
return recommendedItems;
|
||||
});
|
||||
|
||||
const selectedDisplay = computed(() => {
|
||||
return displays.value.find((displayConfig: DisplayConfig) => displayConfig.id === display.value);
|
||||
});
|
||||
const selectedDisplay = computed(() => getDisplay(display.value));
|
||||
|
||||
return { t, selectItems, selectedDisplay, display };
|
||||
},
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
<script lang="ts">
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { getInterface } from '@/interfaces';
|
||||
import { FancySelectItem } from '@/components/v-fancy-select/types';
|
||||
import { InterfaceConfig } from '@directus/shared/types';
|
||||
import { useFieldDetailStore, syncFieldDetailStoreProperty } from '../store/';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import ExtensionOptions from '../shared/extension-options.vue';
|
||||
@@ -40,8 +39,6 @@ export default defineComponent({
|
||||
const { field, interfacesForType } = storeToRefs(fieldDetailStore);
|
||||
const type = computed(() => field.value.type);
|
||||
|
||||
const { interfaces } = getInterfaces();
|
||||
|
||||
const selectItems = computed(() => {
|
||||
const recommendedInterfacesPerType: { [type: string]: string[] } = {
|
||||
string: ['input', 'select-dropdown'],
|
||||
@@ -96,9 +93,7 @@ export default defineComponent({
|
||||
return recommendedItems;
|
||||
});
|
||||
|
||||
const selectedInterface = computed(() => {
|
||||
return interfaces.value.find((inter: InterfaceConfig) => inter.id === interfaceID.value);
|
||||
});
|
||||
const selectedInterface = computed(() => getInterface(interfaceID.value));
|
||||
|
||||
return { t, selectItems, selectedInterface, interfaceID, options };
|
||||
},
|
||||
|
||||
@@ -260,9 +260,7 @@ export default defineComponent({
|
||||
|
||||
const typesWithLabels = computed(() => translate(fieldTypes));
|
||||
|
||||
const typeDisabled = computed(() => {
|
||||
return ['file', 'files', 'o2m', 'm2m', 'm2a', 'm2o', 'translations'].includes(localType.value);
|
||||
});
|
||||
const typeDisabled = computed(() => localType.value !== 'standard');
|
||||
|
||||
const typePlaceholder = computed(() => {
|
||||
if (localType.value === 'm2o') {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
{{ t('type') }}
|
||||
</div>
|
||||
|
||||
<v-select v-model="type" :items="typeOptions" :disabled="typeOptions.length === 1" />
|
||||
<v-select v-model="type" :items="typeOptions" :disabled="typeDisabled" />
|
||||
</div>
|
||||
|
||||
<div class="field half-left">
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { getInterface } from '@/interfaces';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useFieldDetailStore, syncFieldDetailStoreProperty } from '../store/';
|
||||
import { storeToRefs } from 'pinia';
|
||||
@@ -82,9 +82,7 @@ export default defineComponent({
|
||||
const { readyToSave, saving, localType, collection } = storeToRefs(fieldDetail);
|
||||
const { t } = useI18n();
|
||||
|
||||
const { interfaces } = getInterfaces();
|
||||
|
||||
const chosenInterface = computed(() => interfaces.value.find((inter) => inter.id === props.chosenInterface));
|
||||
const chosenInterface = computed(() => getInterface(props.chosenInterface));
|
||||
|
||||
const typeOptions = computed(() => {
|
||||
if (!chosenInterface.value) return [];
|
||||
@@ -95,6 +93,8 @@ export default defineComponent({
|
||||
}));
|
||||
});
|
||||
|
||||
const typeDisabled = computed(() => typeOptions.value.length === 1 || localType.value !== 'standard');
|
||||
|
||||
const key = syncFieldDetailStoreProperty('field.field');
|
||||
const type = syncFieldDetailStoreProperty('field.type');
|
||||
const defaultValue = syncFieldDetailStoreProperty('field.schema.default_value');
|
||||
@@ -105,6 +105,7 @@ export default defineComponent({
|
||||
key,
|
||||
t,
|
||||
type,
|
||||
typeDisabled,
|
||||
typeOptions,
|
||||
defaultValue,
|
||||
required,
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from 'vue';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { getDisplays } from '@/displays';
|
||||
import { getInterface } from '@/interfaces';
|
||||
import { getDisplay } from '@/displays';
|
||||
import { useFieldDetailStore } from '../store/';
|
||||
import { get } from 'lodash';
|
||||
import { storeToRefs } from 'pinia';
|
||||
@@ -53,19 +53,15 @@ export default defineComponent({
|
||||
|
||||
const { collection, field, relations, fields, collections } = storeToRefs(fieldDetail);
|
||||
|
||||
const { interfaces } = getInterfaces();
|
||||
const { displays } = getDisplays();
|
||||
|
||||
const extensionInfo = computed(() => {
|
||||
if (props.type === 'interface') {
|
||||
return interfaces.value.find((inter) => inter.id === props.extension);
|
||||
switch (props.type) {
|
||||
case 'interface':
|
||||
return getInterface(props.extension);
|
||||
case 'display':
|
||||
return getDisplay(props.extension);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
if (props.type === 'display') {
|
||||
return displays.value.find((display) => display.id === props.extension);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
const usesCustomComponent = computed(() => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { set } from 'lodash';
|
||||
import { State, StateUpdates } from '../types';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { getInterface } from '@/interfaces';
|
||||
|
||||
/**
|
||||
* In case a relational field removed the schema object, we'll have to make sure it's re-added
|
||||
@@ -20,7 +20,7 @@ export function resetSchema(updates: StateUpdates, state: State) {
|
||||
export function setLocalTypeForInterface(updates: StateUpdates) {
|
||||
if (!updates.field?.meta?.interface) return;
|
||||
|
||||
const chosenInterface = getInterfaces().interfaces.value.find((inter) => inter.id === updates.field!.meta!.interface);
|
||||
const chosenInterface = getInterface(updates.field.meta.interface);
|
||||
|
||||
if (!chosenInterface) return;
|
||||
|
||||
@@ -36,7 +36,7 @@ export function setLocalTypeForInterface(updates: StateUpdates) {
|
||||
export function setTypeForInterface(updates: StateUpdates, state: State) {
|
||||
if (!updates.field?.meta?.interface) return;
|
||||
|
||||
const chosenInterface = getInterfaces().interfaces.value.find((inter) => inter.id === updates.field!.meta!.interface);
|
||||
const chosenInterface = getInterface(updates.field.meta.interface);
|
||||
|
||||
if (!chosenInterface) return updates;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { HelperFunctions, State, StateUpdates } from '../types';
|
||||
import { getInterface } from '@/interfaces';
|
||||
import { set } from 'lodash';
|
||||
|
||||
export function applyChanges(updates: StateUpdates, _state: State, helperFn: HelperFunctions) {
|
||||
@@ -6,10 +7,11 @@ export function applyChanges(updates: StateUpdates, _state: State, helperFn: Hel
|
||||
|
||||
if (hasChanged('field.type')) {
|
||||
setSpecialForType(updates);
|
||||
updateInterface(updates, helperFn);
|
||||
}
|
||||
}
|
||||
|
||||
export function setSpecialForType(updates: StateUpdates) {
|
||||
function setSpecialForType(updates: StateUpdates) {
|
||||
const type = updates.field?.type;
|
||||
switch (type) {
|
||||
case 'uuid':
|
||||
@@ -26,3 +28,11 @@ export function setSpecialForType(updates: StateUpdates) {
|
||||
set(updates, 'field.meta.special', null);
|
||||
}
|
||||
}
|
||||
|
||||
function updateInterface(updates: StateUpdates, fn: HelperFunctions) {
|
||||
const interface_ = getInterface(fn.getCurrent('field.meta.interface'));
|
||||
const type = updates.field?.type;
|
||||
if (type && !interface_?.types.includes(type)) {
|
||||
set(updates, 'field.meta.interface', undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,13 +141,13 @@
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { defineComponent, PropType, ref, computed } from 'vue';
|
||||
import { useCollectionsStore, useFieldsStore } from '@/stores/';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { getInterface } from '@/interfaces';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { getLocalTypeForField } from '../../get-local-type';
|
||||
import { notify } from '@/utils/notify';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { Field, InterfaceConfig } from '@directus/shared/types';
|
||||
import { Field } from '@directus/shared/types';
|
||||
import FieldSelectMenu from './field-select-menu.vue';
|
||||
import hideDragImage from '@/utils/hide-drag-image';
|
||||
import Draggable from 'vuedraggable';
|
||||
@@ -178,16 +178,13 @@ export default defineComponent({
|
||||
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const fieldsStore = useFieldsStore();
|
||||
const { interfaces } = getInterfaces();
|
||||
|
||||
const editActive = ref(false);
|
||||
|
||||
const { deleteActive, deleting, deleteField } = useDeleteField();
|
||||
const { duplicateActive, duplicateName, collections, duplicateTo, saveDuplicate, duplicating } = useDuplicate();
|
||||
|
||||
const interfaceName = computed(() => {
|
||||
return interfaces.value.find((inter: InterfaceConfig) => inter.id === props.field.meta?.interface)?.name;
|
||||
});
|
||||
const interfaceName = computed(() => getInterface(props.field.meta?.interface)?.name);
|
||||
|
||||
const hidden = computed(() => props.field.meta?.hidden === true);
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ import SettingsNavigation from '../../../components/navigation.vue';
|
||||
import api from '@/api';
|
||||
import { Header } from '@/components/v-table/types';
|
||||
import { useCollectionsStore } from '@/stores/';
|
||||
import { getLayouts } from '@/layouts';
|
||||
import { getLayout } from '@/layouts';
|
||||
import { useRouter } from 'vue-router';
|
||||
import ValueNull from '@/views/private/components/value-null';
|
||||
import PresetsInfoSidebarDetail from './components/presets-info-sidebar-detail.vue';
|
||||
@@ -123,7 +123,6 @@ export default defineComponent({
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const { layouts } = getLayouts();
|
||||
const collectionsStore = useCollectionsStore();
|
||||
|
||||
const selection = ref<Preset[]>([]);
|
||||
@@ -175,7 +174,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const collection = collectionsStore.getCollection(preset.collection)?.name;
|
||||
const layout = layouts.value.find((l) => l.id === preset.layout)?.name;
|
||||
const layout = getLayout(preset.layout)?.name;
|
||||
|
||||
return {
|
||||
id: preset.id,
|
||||
|
||||
Reference in New Issue
Block a user