[]) {
+ const sField = sortField.value;
+ if (sField === null) return;
+
+ const itemsSorted = newItems.map((item, i) => {
+ item[sField] = i;
+ return item;
+ });
+
+ emit(itemsSorted);
+ }
+
+ const sortedItems = computed(() => {
+ const sField = sortField.value;
+ if (sField === null || sort.value.by !== sField) return null;
+
+ const desc = sort.value.desc;
+ const sorted = sortBy(items.value, [sField]);
+ return desc ? sorted.reverse() : sorted;
+ });
+
+ return { sort, sortItems, sortedItems };
+}
diff --git a/app/src/interfaces/one-to-many/one-to-many.vue b/app/src/interfaces/one-to-many/one-to-many.vue
index 1923e32fee..dd015bacc1 100644
--- a/app/src/interfaces/one-to-many/one-to-many.vue
+++ b/app/src/interfaces/one-to-many/one-to-many.vue
@@ -5,10 +5,12 @@
,
default: () => [],
},
+ sortField: {
+ type: String,
+ default: null,
+ },
disabled: {
type: Boolean,
default: false,
@@ -106,14 +113,11 @@ export default defineComponent({
const collectionsStore = useCollectionsStore();
const fieldsStore = useFieldsStore();
- const sortField = computed(() => {
- return relatedCollection.value.meta?.sort_field || null;
- });
-
const { relation, relatedCollection, relatedPrimaryKeyField } = useRelation();
- const { tableHeaders, displayItems, loading, error } = useTable();
+ const { tableHeaders, items, loading, error } = useTable();
const { currentlyEditing, editItem, editsAtStart, stageEdits, cancelEdit } = useEdits();
const { stageSelection, selectModalActive, selectionFilters } = useSelection();
+ const { sort, sortItems, sortedItems } = useSort();
return {
relation,
@@ -128,9 +132,11 @@ export default defineComponent({
stageSelection,
selectModalActive,
deleteItem,
- displayItems,
+ items,
+ sortItems,
selectionFilters,
- sortField,
+ sort,
+ sortedItems,
};
function getItem(id: string | number) {
@@ -207,6 +213,31 @@ export default defineComponent({
);
}
+ function useSort() {
+ const sort = ref({ by: props.sortField || props.fields[0], desc: false });
+
+ function sortItems(newItems: Record[]) {
+ if (props.sortField === null) return;
+
+ const itemsSorted = newItems.map((item, i) => {
+ item[props.sortField] = i;
+ return item;
+ });
+
+ emit('input', itemsSorted);
+ }
+
+ const sortedItems = computed(() => {
+ if (props.sortField === null || sort.value.by !== props.sortField) return null;
+
+ const desc = sort.value.desc;
+ const sorted = sortBy(items.value, [props.sortField]);
+ return desc ? sorted.reverse() : sorted;
+ });
+
+ return { sort, sortItems, sortedItems };
+ }
+
/**
* Holds info about the current relationship, like related collection, primary key field
* of the other collection etc
@@ -230,7 +261,7 @@ export default defineComponent({
// values if it needs to. This allows the user to manually resize the columns for example
const tableHeaders = ref([]);
const loading = ref(false);
- const displayItems = ref[]>([]);
+ const items = ref[]>([]);
const error = ref(null);
watch(
@@ -245,8 +276,8 @@ export default defineComponent({
fields.push(pkField);
}
- if (sortField.value !== null && fields.includes(sortField.value) === false)
- fields.push(sortField.value);
+ if (props.sortField !== null && fields.includes(props.sortField) === false)
+ fields.push(props.sortField);
try {
const endpoint = relatedCollection.value.collection.startsWith('directus_')
@@ -271,7 +302,7 @@ export default defineComponent({
const updatedItems = getUpdatedItems();
const newItems = getNewItems();
- displayItems.value = existingItems
+ items.value = existingItems
.map((item) => {
const updatedItem = updatedItems.find((updated) => updated[pkField] === item[pkField]);
if (updatedItem !== undefined) return updatedItem;
@@ -321,7 +352,7 @@ export default defineComponent({
{ immediate: true }
);
- return { tableHeaders, displayItems, loading, error };
+ return { tableHeaders, items, loading, error };
}
function useEdits() {
@@ -386,11 +417,11 @@ export default defineComponent({
const selectModalActive = ref(false);
const selectedPrimaryKeys = computed<(number | string)[]>(() => {
- if (displayItems.value === null) return [];
+ if (items.value === null) return [];
const pkField = relatedPrimaryKeyField.value.field;
- return displayItems.value
+ return items.value
.filter((currentItem) => pkField in currentItem)
.map((currentItem) => currentItem[pkField]);
});
diff --git a/app/src/interfaces/one-to-many/options.vue b/app/src/interfaces/one-to-many/options.vue
index 4ff0cfc26c..3be649808c 100644
--- a/app/src/interfaces/one-to-many/options.vue
+++ b/app/src/interfaces/one-to-many/options.vue
@@ -11,6 +11,15 @@
:inject="relatedCollectionExists ? null : { fields: newFields, collections: newCollections, relations }"
/>
+
+
{{ $t('sort_field') }}
+
+
@@ -62,6 +71,18 @@ export default defineComponent({
},
});
+ const sortField = computed({
+ get() {
+ return props.value?.sortField;
+ },
+ set(newFields: string) {
+ emit('input', {
+ ...(props.value || {}),
+ sortField: newFields,
+ });
+ },
+ });
+
const relatedCollection = computed(() => {
if (!props.fieldData || !props.relations || props.relations.length === 0) return null;
const { field } = props.fieldData;
@@ -77,7 +98,7 @@ export default defineComponent({
);
});
- return { fields, relatedCollection, relatedCollectionExists };
+ return { fields, sortField, relatedCollection, relatedCollectionExists };
},
});