Refactor field definition and column definition manipulation with record field (#13992)
This PR introduces the usage of record fields in the manipulation of table columns and board fields. Since all of the actual system relies on states like tableColumns, recordIndexFieldDefinitions and the likes, it was required to implement temporary utils that modifies those states in parallel of the new generic currentRecordFields, to keep a working product. With this PR though, currentRecordFields becomes the single source of truth that gets saved to DB, and the remaining work is just to make the switch with this new state on all components that are plugged to tableColumns and the like. This will be done in another PR.
This commit is contained in:
+65
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
computeNewPositionOfRecordWithPosition,
|
||||
type RecordWithPosition,
|
||||
} from '@/object-record/utils/computeNewPositionOfRecordWithPosition';
|
||||
|
||||
const mockRecordsWithPosition: RecordWithPosition[] = [
|
||||
{
|
||||
id: 'A',
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
id: 'B',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
id: 'C',
|
||||
position: 2,
|
||||
},
|
||||
{
|
||||
id: 'D',
|
||||
position: 3,
|
||||
},
|
||||
];
|
||||
|
||||
describe('computeNewPositionOfRecordWithPosition', () => {
|
||||
it('should compute first position', () => {
|
||||
const newPosition = computeNewPositionOfRecordWithPosition({
|
||||
arrayOfRecordsWithPosition: mockRecordsWithPosition,
|
||||
idOfItemToMove: 'B',
|
||||
idOfTargetItem: 'A',
|
||||
});
|
||||
|
||||
expect(newPosition).toEqual(-1);
|
||||
});
|
||||
|
||||
it('should compute last position', () => {
|
||||
const newPosition = computeNewPositionOfRecordWithPosition({
|
||||
arrayOfRecordsWithPosition: mockRecordsWithPosition,
|
||||
idOfItemToMove: 'B',
|
||||
idOfTargetItem: 'D',
|
||||
});
|
||||
|
||||
expect(newPosition).toEqual(4);
|
||||
});
|
||||
|
||||
it('should compute intermediary position after target item', () => {
|
||||
const newPosition = computeNewPositionOfRecordWithPosition({
|
||||
arrayOfRecordsWithPosition: mockRecordsWithPosition,
|
||||
idOfItemToMove: 'A',
|
||||
idOfTargetItem: 'B',
|
||||
});
|
||||
|
||||
expect(newPosition).toEqual(1.5);
|
||||
});
|
||||
|
||||
it('should compute intermediary position before target item', () => {
|
||||
const newPosition = computeNewPositionOfRecordWithPosition({
|
||||
arrayOfRecordsWithPosition: mockRecordsWithPosition,
|
||||
idOfItemToMove: 'A',
|
||||
idOfTargetItem: 'C',
|
||||
});
|
||||
|
||||
expect(newPosition).toEqual(2.5);
|
||||
});
|
||||
});
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { sortByProperty } from '~/utils/array/sortByProperty';
|
||||
|
||||
export type RecordWithPosition = {
|
||||
id: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
export const computeNewPositionOfRecordWithPosition = ({
|
||||
arrayOfRecordsWithPosition,
|
||||
idOfItemToMove,
|
||||
idOfTargetItem,
|
||||
}: {
|
||||
arrayOfRecordsWithPosition: RecordWithPosition[];
|
||||
idOfItemToMove: string;
|
||||
idOfTargetItem: string;
|
||||
}) => {
|
||||
const itemToMove = arrayOfRecordsWithPosition.find(
|
||||
(recordToFind) => recordToFind.id === idOfItemToMove,
|
||||
);
|
||||
|
||||
const targetItem = arrayOfRecordsWithPosition.find(
|
||||
(recordToFind) => recordToFind.id === idOfTargetItem,
|
||||
);
|
||||
|
||||
if (!isDefined(itemToMove)) {
|
||||
throw new Error(`Cannot find item to move for id : ${idOfItemToMove}`);
|
||||
}
|
||||
|
||||
if (!isDefined(targetItem)) {
|
||||
throw new Error(`Cannot find item to move for id : ${idOfTargetItem}`);
|
||||
}
|
||||
|
||||
if (itemToMove.id === targetItem.id) {
|
||||
return itemToMove.position;
|
||||
}
|
||||
|
||||
const targetPosition = targetItem.position;
|
||||
|
||||
const sortedRecordsByAscendingPosition = arrayOfRecordsWithPosition.toSorted(
|
||||
sortByProperty('position'),
|
||||
);
|
||||
|
||||
const indexOfItemToMove = sortedRecordsByAscendingPosition.findIndex(
|
||||
(recordToFind) => recordToFind.id === idOfItemToMove,
|
||||
);
|
||||
const indexOfTargetItem = sortedRecordsByAscendingPosition.findIndex(
|
||||
(recordToFind) => recordToFind.id === idOfTargetItem,
|
||||
);
|
||||
|
||||
const lastIndex = sortedRecordsByAscendingPosition.length - 1;
|
||||
|
||||
const shouldGoToFirstPosition =
|
||||
indexOfItemToMove > 0 && indexOfTargetItem === 0;
|
||||
|
||||
const shouldGoToLastPosition =
|
||||
indexOfItemToMove < lastIndex && indexOfTargetItem === lastIndex;
|
||||
|
||||
if (shouldGoToFirstPosition) {
|
||||
return targetPosition - 1;
|
||||
} else if (shouldGoToLastPosition) {
|
||||
return targetPosition + 1;
|
||||
} else {
|
||||
const shouldGoAfterTargetItem = indexOfItemToMove < indexOfTargetItem;
|
||||
|
||||
if (shouldGoAfterTargetItem) {
|
||||
const itemAfterTargetItem =
|
||||
sortedRecordsByAscendingPosition[indexOfTargetItem + 1];
|
||||
|
||||
const intermediaryPosition =
|
||||
targetItem.position +
|
||||
(itemAfterTargetItem.position - targetItem.position) / 2;
|
||||
|
||||
return intermediaryPosition;
|
||||
} else {
|
||||
const itemBeforeTargetItem =
|
||||
sortedRecordsByAscendingPosition[indexOfTargetItem - 1];
|
||||
|
||||
const intermediaryPosition =
|
||||
targetItem.position -
|
||||
(targetItem.position - itemBeforeTargetItem.position) / 2;
|
||||
|
||||
return intermediaryPosition;
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user