Repository: directus/directus
File: app/src/modules/content/comparison-utils.ts (TypeScript)

Code before:
		}

		// Skip related item fields when comparing revisions
		if (comparisonType === 'revision' && fieldMetadata && fieldMetadata[fieldKey]) {
			const field = fieldMetadata[fieldKey];
			const localType = field.meta?.special?.[0];

			// Exclude relational field types from revision comparison
			if (isRelationalField(localType)) {
				return false;
			}
		}

		const incomingValue = comparedData.incoming[fieldKey];
		const baseValue = comparedData.base[fieldKey];

		return !isEqual(incomingValue, baseValue);
	});
}

export function getVersionDisplayName(version: ContentVersion): string {
	return isNil(version.name) ? version.key : version.name;
}

export function isRelationalField(localType: string | undefined): boolean {
	return localType ? ['m2o', 'o2m', 'm2m', 'm2a', 'files', 'translations'].includes(localType) : false;
}

export function addFieldToSelection(selectedFields: string[], field: string): string[] {
	return [...selectedFields, field];
}

export function removeFieldFromSelection(selectedFields: string[], field: string): string[] {
	return selectedFields.filter((f: string) => f !== field);
}

export function toggleFieldInSelection(selectedFields: string[], field: string): string[] {
	if (selectedFields.includes(field)) {
		return removeFieldFromSelection(selectedFields, field);
	} else {
		return addFieldToSelection(selectedFields, field);
	}
}

export function toggleAllFields(selectedFields: string[], availableFields: string[], allSelected: boolean): string[] {
	if (allSelected) {
		return [];
	} else {
		return [...new Set([...selectedFields, ...availableFields])];
	}
}

Review comment (suggestion):
Let’s ensure to determine the `localType` correctly — please have a look at app/src/utils/get-local-type.ts. Please also note the other [comment](https://github.com/directus/directus/pull/25954#discussion_r2416136652).

Code after:
		const baseValue = comparedData.base[fieldKey];

		return !isEqual(incomingValue, baseValue);
	});
}

export function getVersionDisplayName(version: ContentVersion): string {
	return isNil(version.name) ? version.key : version.name;
}

export function isRelationalField(field: Field): boolean {
	const RELATIONAL_TYPES = ['file', 'files', 'm2o', 'o2m', 'm2m', 'm2a', 'translations'];
	return field.meta?.special?.find((type) => RELATIONAL_TYPES.includes(type)) !== undefined;
}

export function addFieldToSelection(selectedFields: string[], field: string): string[] {
	return [...selectedFields, field];
}

export function removeFieldFromSelection(selectedFields: string[], field: string): string[] {
	return selectedFields.filter((f: string) => f !== field);
}

export function toggleFieldInSelection(selectedFields: string[], field: string): string[] {
	if (selectedFields.includes(field)) {
		return removeFieldFromSelection(selectedFields, field);
	} else {
		return addFieldToSelection(selectedFields, field);
	}
}

export function toggleAllFields(selectedFields: string[], availableFields: string[], allSelected: boolean): string[] {
	if (allSelected) {
		return [];
	} else {
		return [...new Set([...selectedFields, ...availableFields])];
	}
}

export function areAllFieldsSelected(selectedFields: string[], availableFields: string[]): boolean {
	return availableFields.length > 0 && availableFields.every((field) => selectedFields.includes(field));
}

export function areSomeFieldsSelected(selectedFields: string[], availableFields: string[]): boolean {
	return availableFields.length > 0 && availableFields.some((field) => selectedFields.includes(field));
}

export function normalizeUser(user: User | string | null | undefined): NormalizedUser | null {
	if (!user) return null;

	// Handle string user ID