From c80fa6d6b9501bbbebbcde21bcb38ec617b4d0a7 Mon Sep 17 00:00:00 2001 From: Azri Kahar <42867097+azrikahar@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:47:15 +0800 Subject: [PATCH] Assign sort number when creating field(s) (#18877) Co-authored-by: Jan Arends Co-authored-by: Rijk van Zanten Co-authored-by: Pascal Jufer --- .changeset/dull-kings-marry.md | 5 +++++ api/src/services/collections.ts | 27 +++++++++++++++++++++++++-- api/src/services/fields.ts | 12 ++++++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 .changeset/dull-kings-marry.md diff --git a/.changeset/dull-kings-marry.md b/.changeset/dull-kings-marry.md new file mode 100644 index 0000000000..27c50e2d36 --- /dev/null +++ b/.changeset/dull-kings-marry.md @@ -0,0 +1,5 @@ +--- +'@directus/api': patch +--- + +Implemented sort number for fields in collections on creation to ensure order is always retained diff --git a/api/src/services/collections.ts b/api/src/services/collections.ts index 94cfac34b7..e98ffc2252 100644 --- a/api/src/services/collections.ts +++ b/api/src/services/collections.ts @@ -4,7 +4,7 @@ import type { Accountability, FieldMeta, RawField, SchemaOverview } from '@direc import { addFieldFlag } from '@directus/utils'; import type Keyv from 'keyv'; import type { Knex } from 'knex'; -import { chunk, omit } from 'lodash-es'; +import { chunk, groupBy, merge, omit } from 'lodash-es'; import { clearSystemCache, getCache } from '../cache.js'; import { ALIAS_TYPES } from '../constants.js'; import type { Helpers } from '../database/helpers/index.js'; @@ -145,7 +145,30 @@ export class CollectionsService { const fieldPayloads = payload.fields!.filter((field) => field.meta).map((field) => field.meta) as FieldMeta[]; - await fieldItemsService.createMany(fieldPayloads, { + // Sort new fields that does not have any group defined, in ascending order. + // Lodash merge is used so that the "sort" can be overridden if defined. + let sortedFieldPayloads = fieldPayloads + .filter((field) => field?.group === undefined || field?.group === null) + .map((field, index) => merge({ sort: index + 1 }, field)); + + // Sort remaining new fields with group defined, if any, in ascending order. + // sortedFieldPayloads will be less than fieldPayloads if it filtered out any fields with group defined. + if (sortedFieldPayloads.length < fieldPayloads.length) { + const fieldsWithGroups = groupBy( + fieldPayloads.filter((field) => field?.group), + (field) => field?.group + ); + + // The sort order is restarted from 1 for fields in each group and appended to sortedFieldPayloads. + // Lodash merge is used so that the "sort" can be overridden if defined. + for (const [_group, fields] of Object.entries(fieldsWithGroups)) { + sortedFieldPayloads = sortedFieldPayloads.concat( + fields.map((field, index) => merge({ sort: index + 1 }, field)) + ); + } + } + + await fieldItemsService.createMany(sortedFieldPayloads, { bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params), bypassLimits: true, diff --git a/api/src/services/fields.ts b/api/src/services/fields.ts index 0e29176415..3cb0e48832 100644 --- a/api/src/services/fields.ts +++ b/api/src/services/fields.ts @@ -5,7 +5,7 @@ import type { Accountability, Field, FieldMeta, RawField, SchemaOverview, Type } import { addFieldFlag, toArray } from '@directus/utils'; import type Keyv from 'keyv'; import type { Knex } from 'knex'; -import { isEqual, isNil } from 'lodash-es'; +import { isEqual, isNil, merge } from 'lodash-es'; import { clearSystemCache, getCache } from '../cache.js'; import { ALIAS_TYPES } from '../constants.js'; import { translateDatabaseError } from '../database/errors/translate.js'; @@ -308,9 +308,17 @@ export class FieldsService { } if (hookAdjustedField.meta) { + const existingSortRecord: Record<'max', number | null> | undefined = await trx + .from('directus_fields') + .where(hookAdjustedField.meta?.group ? { collection, group: hookAdjustedField.meta.group } : { collection }) + .max('sort', { as: 'max' }) + .first(); + + const newSortValue: number = existingSortRecord?.max ? existingSortRecord.max + 1 : 1; + await itemsService.createOne( { - ...hookAdjustedField.meta, + ...merge({ sort: newSortValue }, hookAdjustedField.meta), collection: collection, field: hookAdjustedField.field, },