mirror of
https://github.com/directus/directus.git
synced 2026-01-26 06:28:00 -05:00
Fix a few dev mode warnings (#18249)
* `list-m2m` make layout optional * Silence a few more warnings * Properly type v-button `to` * Make search prop in field-detail-simple not required * Set undefined as default value for text in v-text-overflow * Change initial search value to undefined in field-detail * Rework field-detail and field-detail-simple to use script setup * One less ctrl+z * Remove unnecessary new line --------- Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { RouteLocation, useRoute, useLink } from 'vue-router';
|
||||
import { RouteLocationRaw, useRoute, useLink } from 'vue-router';
|
||||
import { useSizeClass, useGroupable } from '@directus/composables';
|
||||
import { isEqual, isNil } from 'lodash';
|
||||
|
||||
@@ -64,7 +64,7 @@ interface Props {
|
||||
/** Show a circular progress bar */
|
||||
loading?: boolean;
|
||||
/** To what internal link the button should direct */
|
||||
to?: string | RouteLocation;
|
||||
to?: RouteLocationRaw;
|
||||
/** To what external link the button should direct */
|
||||
href?: string;
|
||||
/** Renders the button highlighted */
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useElementSize } from '@directus/composables';
|
||||
|
||||
interface Props {
|
||||
/** The text that should be displayed */
|
||||
text: string | number | boolean | Record<string, any> | Array<any>;
|
||||
text?: string | number | boolean | Record<string, any> | Array<any>;
|
||||
/** What parts of the text should be highlighted */
|
||||
highlight?: string;
|
||||
/** The placement of the tooltip */
|
||||
@@ -19,6 +19,7 @@ interface Props {
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
text: undefined,
|
||||
highlight: undefined,
|
||||
placement: 'top',
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useCollection } from '@directus/composables';
|
||||
import { getEndpoint } from '@directus/utils';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { mergeWith } from 'lodash';
|
||||
import { computed, ComputedRef, Ref, ref, unref, watch } from 'vue';
|
||||
import { computed, ComputedRef, isRef, Ref, ref, unref, watch } from 'vue';
|
||||
import { usePermissions } from './use-permissions';
|
||||
import { Field, Query, Relation } from '@directus/types';
|
||||
import { getDefaultValuesFromFields } from '@/utils/get-default-values-from-fields';
|
||||
@@ -79,7 +79,7 @@ export function useItem(
|
||||
|
||||
const defaultValues = getDefaultValuesFromFields(fieldsWithPermissions);
|
||||
|
||||
watch([collection, primaryKey, query], refresh, { immediate: true });
|
||||
watch([collection, primaryKey, ...(isRef(query) ? [query] : [])], refresh, { immediate: true });
|
||||
|
||||
return {
|
||||
edits,
|
||||
|
||||
@@ -225,7 +225,7 @@ const props = withDefaults(
|
||||
collection: string;
|
||||
field: string;
|
||||
width: string;
|
||||
layout: LAYOUTS;
|
||||
layout?: LAYOUTS;
|
||||
tableSpacing?: 'compact' | 'cozy' | 'comfortable';
|
||||
fields?: Array<string>;
|
||||
template?: string | null;
|
||||
|
||||
@@ -222,7 +222,7 @@ const props = withDefaults(
|
||||
collection: string;
|
||||
field: string;
|
||||
width: string;
|
||||
layout: LAYOUTS;
|
||||
layout?: LAYOUTS;
|
||||
tableSpacing?: 'compact' | 'cozy' | 'comfortable';
|
||||
fields?: Array<string>;
|
||||
template?: string | null;
|
||||
|
||||
@@ -38,142 +38,138 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed, toRefs, watch } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { computed, toRefs, watch } from 'vue';
|
||||
import { Collection } from '@directus/types';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { orderBy } from 'lodash';
|
||||
import { useFieldDetailStore, syncFieldDetailStoreProperty } from '../store/';
|
||||
import { syncRefProperty } from '@/utils/sync-ref-property';
|
||||
import { syncFieldDetailStoreProperty, useFieldDetailStore } from '../store/';
|
||||
import FieldConfiguration from './field-configuration.vue';
|
||||
import { useExtensions } from '@/extensions';
|
||||
|
||||
export default defineComponent({
|
||||
components: { FieldConfiguration },
|
||||
props: {
|
||||
collection: {
|
||||
type: Object as PropType<Collection>,
|
||||
required: true,
|
||||
},
|
||||
search: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ['save', 'toggleAdvanced'],
|
||||
setup(props) {
|
||||
const { collection, search } = toRefs(props);
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
collection: Collection;
|
||||
search: string | null;
|
||||
}>(),
|
||||
{
|
||||
search: null,
|
||||
}
|
||||
);
|
||||
|
||||
const { t } = useI18n();
|
||||
defineEmits<{
|
||||
(e: 'save'): void;
|
||||
(e: 'toggleAdvanced'): void;
|
||||
}>();
|
||||
|
||||
const fieldDetail = useFieldDetailStore();
|
||||
watch(collection, () => fieldDetail.update({ collection: collection.value.collection }), { immediate: true });
|
||||
const { collection, search } = toRefs(props);
|
||||
|
||||
const { interfaces } = useExtensions();
|
||||
const { t } = useI18n();
|
||||
|
||||
const interfacesSorted = computed(() => {
|
||||
return orderBy(
|
||||
interfaces.value.filter((inter) => !inter.system),
|
||||
['order']
|
||||
);
|
||||
});
|
||||
const fieldDetail = useFieldDetailStore();
|
||||
watch(collection, () => fieldDetail.update({ collection: collection.value.collection }), { immediate: true });
|
||||
|
||||
const groups = computed(() => {
|
||||
const groupsWithInterfaces = [
|
||||
{
|
||||
key: 'standard',
|
||||
name: t('interface_group_text_and_numbers'),
|
||||
interfaces: filterInterfacesByGroup('standard'),
|
||||
},
|
||||
{
|
||||
key: 'selection',
|
||||
name: t('interface_group_selection'),
|
||||
interfaces: filterInterfacesByGroup('selection'),
|
||||
},
|
||||
{
|
||||
key: 'relational',
|
||||
name: t('interface_group_relational'),
|
||||
interfaces: filterInterfacesByGroup('relational'),
|
||||
},
|
||||
{
|
||||
key: 'presentation',
|
||||
name: t('interface_group_presentation'),
|
||||
interfaces: filterInterfacesByGroup('presentation'),
|
||||
},
|
||||
{
|
||||
key: 'group',
|
||||
name: t('interface_group_groups'),
|
||||
interfaces: filterInterfacesByGroup('group'),
|
||||
},
|
||||
{
|
||||
key: 'other',
|
||||
name: t('interface_group_other'),
|
||||
interfaces: filterInterfacesByGroup('other'),
|
||||
},
|
||||
];
|
||||
const { interfaces } = useExtensions();
|
||||
|
||||
if (!search.value) return groupsWithInterfaces;
|
||||
|
||||
return groupsWithInterfaces.filter((group) => group.interfaces.length > 0);
|
||||
|
||||
function filterInterfacesByGroup(group: string) {
|
||||
const filteredInterfaces = interfacesSorted.value.filter((inter) => (inter.group ?? 'other') === group);
|
||||
if (!search.value) return filteredInterfaces;
|
||||
const searchValue = search.value!.toLowerCase();
|
||||
return filteredInterfaces.filter(
|
||||
(inter) => inter.id.toLowerCase().includes(searchValue) || inter.name.toLowerCase().includes(searchValue)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const chosenInterface = syncFieldDetailStoreProperty('field.meta.interface');
|
||||
|
||||
const configRow = computed(() => {
|
||||
if (!chosenInterface.value) return null;
|
||||
|
||||
let indexInGroup: number | null = null;
|
||||
|
||||
groups.value.forEach((group) => {
|
||||
const index = group.interfaces.findIndex((inter) => inter.id === chosenInterface.value);
|
||||
if (index !== -1) indexInGroup = index;
|
||||
});
|
||||
|
||||
if (indexInGroup === null) return null;
|
||||
|
||||
const windowWidth = window.innerWidth;
|
||||
|
||||
let columns = 1;
|
||||
|
||||
if (windowWidth > 400) {
|
||||
columns = 2;
|
||||
}
|
||||
|
||||
if (windowWidth > 600) {
|
||||
columns = 3;
|
||||
}
|
||||
|
||||
if (windowWidth > 840) {
|
||||
columns = 4;
|
||||
}
|
||||
|
||||
return Math.ceil((indexInGroup + 1) / columns) + 1;
|
||||
});
|
||||
|
||||
return { t, interfaces, groups, isSVG, syncRefProperty, chosenInterface, configRow, toggleInterface };
|
||||
|
||||
function isSVG(path: string) {
|
||||
return path.startsWith('<svg');
|
||||
}
|
||||
|
||||
function toggleInterface(id: string) {
|
||||
if (chosenInterface.value === id) {
|
||||
chosenInterface.value = null;
|
||||
} else {
|
||||
chosenInterface.value = id;
|
||||
}
|
||||
}
|
||||
},
|
||||
const interfacesSorted = computed(() => {
|
||||
return orderBy(
|
||||
interfaces.value.filter((inter) => !inter.system),
|
||||
['order']
|
||||
);
|
||||
});
|
||||
|
||||
const groups = computed(() => {
|
||||
const groupsWithInterfaces = [
|
||||
{
|
||||
key: 'standard',
|
||||
name: t('interface_group_text_and_numbers'),
|
||||
interfaces: filterInterfacesByGroup('standard'),
|
||||
},
|
||||
{
|
||||
key: 'selection',
|
||||
name: t('interface_group_selection'),
|
||||
interfaces: filterInterfacesByGroup('selection'),
|
||||
},
|
||||
{
|
||||
key: 'relational',
|
||||
name: t('interface_group_relational'),
|
||||
interfaces: filterInterfacesByGroup('relational'),
|
||||
},
|
||||
{
|
||||
key: 'presentation',
|
||||
name: t('interface_group_presentation'),
|
||||
interfaces: filterInterfacesByGroup('presentation'),
|
||||
},
|
||||
{
|
||||
key: 'group',
|
||||
name: t('interface_group_groups'),
|
||||
interfaces: filterInterfacesByGroup('group'),
|
||||
},
|
||||
{
|
||||
key: 'other',
|
||||
name: t('interface_group_other'),
|
||||
interfaces: filterInterfacesByGroup('other'),
|
||||
},
|
||||
];
|
||||
|
||||
if (!search.value) return groupsWithInterfaces;
|
||||
|
||||
return groupsWithInterfaces.filter((group) => group.interfaces.length > 0);
|
||||
|
||||
function filterInterfacesByGroup(group: string) {
|
||||
const filteredInterfaces = interfacesSorted.value.filter((inter) => (inter.group ?? 'other') === group);
|
||||
if (!search.value) return filteredInterfaces;
|
||||
const searchValue = search.value!.toLowerCase();
|
||||
return filteredInterfaces.filter(
|
||||
(inter) => inter.id.toLowerCase().includes(searchValue) || inter.name.toLowerCase().includes(searchValue)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const chosenInterface = syncFieldDetailStoreProperty('field.meta.interface');
|
||||
|
||||
const configRow = computed(() => {
|
||||
if (!chosenInterface.value) return null;
|
||||
|
||||
let indexInGroup: number | null = null;
|
||||
|
||||
groups.value.forEach((group) => {
|
||||
const index = group.interfaces.findIndex((inter) => inter.id === chosenInterface.value);
|
||||
if (index !== -1) indexInGroup = index;
|
||||
});
|
||||
|
||||
if (indexInGroup === null) return null;
|
||||
|
||||
const windowWidth = window.innerWidth;
|
||||
|
||||
let columns = 1;
|
||||
|
||||
if (windowWidth > 400) {
|
||||
columns = 2;
|
||||
}
|
||||
|
||||
if (windowWidth > 600) {
|
||||
columns = 3;
|
||||
}
|
||||
|
||||
if (windowWidth > 840) {
|
||||
columns = 4;
|
||||
}
|
||||
|
||||
return Math.ceil((indexInGroup + 1) / columns) + 1;
|
||||
});
|
||||
|
||||
function isSVG(path: string) {
|
||||
return path.startsWith('<svg');
|
||||
}
|
||||
|
||||
function toggleInterface(id: string) {
|
||||
if (chosenInterface.value === id) {
|
||||
chosenInterface.value = null;
|
||||
} else {
|
||||
chosenInterface.value = id;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
</v-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, computed, toRefs, watch } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, toRefs, watch } from 'vue';
|
||||
import { LocalType } from '@directus/types';
|
||||
import { useFieldDetailStore } from './store/';
|
||||
import FieldDetailSimple from './field-detail-simple/field-detail-simple.vue';
|
||||
@@ -55,88 +55,81 @@ import { useDialogRoute } from '@/composables/use-dialog-route';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FieldDetail',
|
||||
components: { FieldDetailSimple, FieldDetailAdvanced, FieldDetailAdvancedTabs, FieldDetailAdvancedActions },
|
||||
props: {
|
||||
collection: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
field: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<LocalType>,
|
||||
default: null,
|
||||
},
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
collection: string;
|
||||
field: string;
|
||||
type: LocalType | null;
|
||||
}>(),
|
||||
{
|
||||
type: null,
|
||||
}
|
||||
);
|
||||
|
||||
const { collection, field, type } = toRefs(props);
|
||||
|
||||
const search = ref<string | null>(null);
|
||||
|
||||
const isOpen = useDialogRoute();
|
||||
|
||||
const fieldDetail = useFieldDetailStore();
|
||||
|
||||
const { editing } = storeToRefs(fieldDetail);
|
||||
|
||||
watch(
|
||||
[field, type],
|
||||
() => {
|
||||
if (!type.value) return;
|
||||
|
||||
fieldDetail.startEditing(collection.value, field.value, type.value);
|
||||
},
|
||||
setup(props) {
|
||||
const { collection } = toRefs(props);
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const search = ref<string | null>(null);
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const fieldsStore = useFieldsStore();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
||||
const isOpen = useDialogRoute();
|
||||
|
||||
const fieldDetail = useFieldDetailStore();
|
||||
|
||||
const { editing } = storeToRefs(fieldDetail);
|
||||
|
||||
watch(
|
||||
() => props.field,
|
||||
() => fieldDetail.startEditing(props.collection, props.field, props.type),
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const fieldsStore = useFieldsStore();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
||||
const collectionInfo = computed(() => {
|
||||
return collectionsStore.getCollection(collection.value);
|
||||
});
|
||||
|
||||
const simple = ref(props.type === null);
|
||||
|
||||
const title = computed(() => {
|
||||
const existingField = fieldsStore.getField(props.collection, props.field);
|
||||
const fieldName = existingField?.name || formatTitle(fieldDetail.field.name || '');
|
||||
|
||||
if (props.field === '+' && fieldName === '') {
|
||||
return t('creating_new_field', { collection: collectionInfo.value?.name });
|
||||
} else {
|
||||
return t('field_in_collection', { field: fieldName, collection: collectionInfo.value?.name });
|
||||
}
|
||||
});
|
||||
|
||||
const currentTab = ref(['schema']);
|
||||
|
||||
const showAdvanced = computed(() => {
|
||||
return editing.value !== '+' || !simple.value;
|
||||
});
|
||||
|
||||
return { search, simple, cancel, collectionInfo, t, title, save, isOpen, currentTab, showAdvanced };
|
||||
|
||||
async function cancel() {
|
||||
await router.push(`/settings/data-model/${props.collection}`);
|
||||
fieldDetail.$reset();
|
||||
}
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
await fieldDetail.save();
|
||||
} catch (err: any) {
|
||||
unexpectedError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
router.push(`/settings/data-model/${props.collection}`);
|
||||
fieldDetail.$reset();
|
||||
}
|
||||
},
|
||||
const collectionInfo = computed(() => {
|
||||
return collectionsStore.getCollection(collection.value);
|
||||
});
|
||||
|
||||
const simple = ref(props.type === null);
|
||||
|
||||
const title = computed(() => {
|
||||
const existingField = fieldsStore.getField(props.collection, props.field);
|
||||
const fieldName = existingField?.name || formatTitle(fieldDetail.field.name || '');
|
||||
|
||||
if (props.field === '+' && fieldName === '') {
|
||||
return t('creating_new_field', { collection: collectionInfo.value?.name });
|
||||
} else {
|
||||
return t('field_in_collection', { field: fieldName, collection: collectionInfo.value?.name });
|
||||
}
|
||||
});
|
||||
|
||||
const currentTab = ref(['schema']);
|
||||
|
||||
const showAdvanced = computed(() => {
|
||||
return editing.value !== '+' || !simple.value;
|
||||
});
|
||||
|
||||
async function cancel() {
|
||||
await router.push(`/settings/data-model/${props.collection}`);
|
||||
fieldDetail.$reset();
|
||||
}
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
await fieldDetail.save();
|
||||
} catch (err: any) {
|
||||
unexpectedError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
router.push(`/settings/data-model/${props.collection}`);
|
||||
fieldDetail.$reset();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user