diff --git a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/Filters.tsx b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/Filters.tsx index cb2285bee716e5..6416977b428105 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/Filters.tsx +++ b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/Filters.tsx @@ -255,6 +255,17 @@ function Filters({ getFilters(); }, [dataSet]); + const updateEntityFieldType = ({item}: {item: IFilter}): string => { + let entityFieldType = ''; + visit(fields, (field: IFieldTreeItem) => { + if (field.name === item.fieldName && field.entityFieldType) { + entityFieldType = field.entityFieldType; + } + }); + + return entityFieldType; + }; + const updateFiltersOrder = async ({ filtersOrder, }: { @@ -426,6 +437,7 @@ function Filters({ noFilterClientExtensionsAvailableModal(); } else { + item.entityFieldType = updateEntityFieldType({item}); setActiveMode(FILTER_MODE.EDITION); setActiveFilter(item); } diff --git a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/SelectionFilter.tsx b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/SelectionFilter.tsx index 17d493a114814f..78374be98a7965 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/SelectionFilter.tsx +++ b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/SelectionFilter.tsx @@ -17,6 +17,7 @@ import React, {useState} from 'react'; import CheckboxMultiSelect from '../../../../components/CheckboxMultiSelect'; import RequiredMark from '../../../../components/RequiredMark'; import { + EFieldType, ESelectionFilterSourceType, IField, IFilter, @@ -81,12 +82,20 @@ function Body({ const [multiple, setMultiple] = useState(filter?.multiple ?? true); const [picklists, setPicklists] = useState(); - const [preselectedValueInput, setPreselectedValueInput] = useState(''); + const [preselectedValueInput, setPreselectedValueInput] = useState< + string | number + >(''); const [preselectedValues, setPreselectedValues] = useState( JSON.parse(filter?.preselectedValues || '[]') ); const [selectedField, setSelectedField] = useState( - filter ? {label: filter.fieldName, name: filter.fieldName} : undefined + filter + ? { + entityFieldType: filter.entityFieldType, + label: filter.fieldName, + name: filter.fieldName, + } + : undefined ); const [source, setSource] = useState(filter?.source); const [sourceType, setSourceType] = useState(filter?.sourceType); @@ -214,6 +223,7 @@ function Body({ if (success) { let formData: any = { + entityFieldType: selectedField?.entityFieldType, fieldName: selectedField?.name, include: includeMode === 'include', label_i18n: i18nFilterLabels, @@ -221,7 +231,11 @@ function Body({ preselectedValues: JSON.stringify( preselectedValues.map((item: any) => ({ label: item.label, - value: item.value, + value: + selectedField?.entityFieldType === + EFieldType.INTEGER + ? Number(item.value) + : item.value, })) ), source, diff --git a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/source_type/ApiRestApplication.tsx b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/source_type/ApiRestApplication.tsx index 4deed8fd4d890c..c369766dd7cad9 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/source_type/ApiRestApplication.tsx +++ b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/data_set/filters/components/selection_filter/source_type/ApiRestApplication.tsx @@ -50,7 +50,7 @@ interface IApiRestApplicationModalContentProps { selectedRESTSchema: string | null; sourceItems: TItem[]; }) => void; - preselectedValueInput: string; + preselectedValueInput: string | number; requiredRESTApplicationValidationError: boolean; resolvedRESTSchemas: string[]; restApplications: string[]; @@ -119,7 +119,7 @@ function ApiRestApplication({ selectedItemLabel, source, }: { - preselectedValueInput: string; + preselectedValueInput: string | number; selectedItemKey: string; selectedItemLabel: string; source: string | null; diff --git a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/getFields.ts b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/getFields.ts index 9fd3130c2fddd9..cd36566d57954b 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/getFields.ts +++ b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/getFields.ts @@ -128,6 +128,8 @@ function getValidFields({ }); } + field.entityFieldType = type; + fields.push(field); }); diff --git a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/types.ts b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/types.ts index 531142ae612711..cad99a1c9d2e2f 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/types.ts +++ b/modules/apps/frontend-data-set/frontend-data-set-admin-web/src/main/resources/META-INF/resources/js/utils/types.ts @@ -93,6 +93,7 @@ export interface IDateFilter extends IFilter { export interface IField { children?: Array; + entityFieldType?: string; format?: EFieldFormat; id?: string; label?: string; @@ -113,6 +114,7 @@ export interface IFieldTreeItem extends IField { } export interface IFilter extends IOrderable { + entityFieldType?: string; fieldName: string; filterType?: EFilterType; include?: boolean; diff --git a/modules/apps/frontend-data-set/frontend-data-set-api/src/main/java/com/liferay/frontend/data/set/constants/FDSEntityFieldTypes.java b/modules/apps/frontend-data-set/frontend-data-set-api/src/main/java/com/liferay/frontend/data/set/constants/FDSEntityFieldTypes.java index 7f1d9c805e3783..bbe56f9e79f9c4 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-api/src/main/java/com/liferay/frontend/data/set/constants/FDSEntityFieldTypes.java +++ b/modules/apps/frontend-data-set/frontend-data-set-api/src/main/java/com/liferay/frontend/data/set/constants/FDSEntityFieldTypes.java @@ -16,6 +16,8 @@ public class FDSEntityFieldTypes { public static final String DATE_TIME = "date-time"; + public static final String INTEGER = "integer"; + public static final String STRING = "string"; } \ No newline at end of file diff --git a/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializer.java b/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializer.java index c2d8844eed454b..bf7b6d6eda0e49 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializer.java +++ b/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializer.java @@ -895,7 +895,14 @@ private JSONObject _serializeFilterClientExtension( return JSONUtil.put( "clientExtensionFilterURL", fdsFilterCET.getURL() ).put( - "entityFieldType", FDSEntityFieldTypes.STRING + "entityFieldType", + () -> { + if (Validator.isNotNull(properties.get("entityFieldType"))) { + return properties.get("entityFieldType"); + } + + return FDSEntityFieldTypes.STRING; + } ).put( "id", fieldName ).put( @@ -964,6 +971,10 @@ private JSONObject _serializeFilterSelection( Map properties, String sourceType) throws Exception { + String entityFieldType = properties.get( + "entityFieldType" + ).toString(); + if (Objects.equals( sourceType, FDSEntryItemImportPolicy.ITEM_PROXY.toString())) { @@ -987,6 +998,10 @@ private JSONObject _serializeFilterSelection( ).put( "entityFieldType", () -> { + if (Validator.isNotNull(entityFieldType)) { + return entityFieldType; + } + if (_isCollection( String.valueOf(properties.get("fieldName")), sourceType)) { @@ -997,20 +1012,7 @@ private JSONObject _serializeFilterSelection( return FDSEntityFieldTypes.STRING; } ).put( - "id", - () -> { - if (!Objects.equals(sourceType, "OBJECT_PICKLIST")) { - return fieldName; - } - - int index = fieldName.lastIndexOf(StringPool.FORWARD_SLASH); - - if (index <= 0) { - return fieldName; - } - - return fieldName.substring(0, index); - } + "id", fieldName ).put( "label", MapUtil.getWithFallbackKey(properties, "label", "fieldName") @@ -1075,7 +1077,17 @@ private JSONObject _serializeFilterSelection( listTypeEntry.getName( PortalUtil.getLocale(httpServletRequest)) ).put( - "value", listTypeEntry.getKey() + "value", + () -> { + if (Validator.isNotNull(entityFieldType) && + StringUtil.equalsIgnoreCase( + entityFieldType, FDSEntityFieldTypes.INTEGER)) { + + return Integer.valueOf(listTypeEntry.getKey()); + } + + return listTypeEntry.getKey(); + } )) ).put( "preloadedData", @@ -1106,7 +1118,19 @@ private JSONObject _serializeFilterSelection( listTypeEntry.getName( PortalUtil.getLocale(httpServletRequest)) ).put( - "value", listTypeEntry.getKey() + "value", + () -> { + if (Validator.isNotNull(entityFieldType) && + StringUtil.equalsIgnoreCase( + entityFieldType, + FDSEntityFieldTypes.INTEGER)) { + + return Integer.valueOf( + listTypeEntry.getKey()); + } + + return listTypeEntry.getKey(); + } )); } } diff --git a/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/resources/com/liferay/frontend/data/set/internal/batch/01-object-definition.batch-engine-data.json b/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/resources/com/liferay/frontend/data/set/internal/batch/01-object-definition.batch-engine-data.json index d28e29a9dfbc32..1047abca815b6a 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/resources/com/liferay/frontend/data/set/internal/batch/01-object-definition.batch-engine-data.json +++ b/modules/apps/frontend-data-set/frontend-data-set-impl/src/main/resources/com/liferay/frontend/data/set/internal/batch/01-object-definition.batch-engine-data.json @@ -1089,6 +1089,22 @@ "system": true, "type": "Boolean" }, + { + "DBType": "String", + "businessType": "Text", + "externalReferenceCode": "ENTITY_FIELD_TYPE", + "indexed": true, + "indexedAsKeyword": false, + "label": { + "en_US": "Entity Field Type" + }, + "localized": false, + "name": "entityFieldType", + "required": false, + "state": false, + "system": true, + "type": "String" + }, { "DBType": "String", "businessType": "Text", diff --git a/modules/apps/frontend-data-set/frontend-data-set-impl/src/test/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializerTest.java b/modules/apps/frontend-data-set/frontend-data-set-impl/src/test/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializerTest.java index de5f3aea1ba53c..4c2b45f3b8b529 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-impl/src/test/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializerTest.java +++ b/modules/apps/frontend-data-set/frontend-data-set-impl/src/test/java/com/liferay/frontend/data/set/internal/serializer/CustomFDSSerializerTest.java @@ -563,6 +563,8 @@ public boolean isReadOnly() { _mockSerializeFilters( FDS_NAMES[0], HashMapBuilder.put( + "entityFieldType", FDSEntityFieldTypes.INTEGER + ).put( "fieldName", FIELD_NAMES[0] ).put( "include", true @@ -602,7 +604,7 @@ public boolean isReadOnly() { ).put( "autocompleteEnabled", true ).put( - "entityFieldType", "string" + "entityFieldType", FDSEntityFieldTypes.INTEGER ).put( "id", FIELD_NAMES[0] ).put( diff --git a/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/implementation/SelectionFilter.tsx b/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/implementation/SelectionFilter.tsx index b6acf1612c6719..8f75fb44050b4b 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/implementation/SelectionFilter.tsx +++ b/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/implementation/SelectionFilter.tsx @@ -114,13 +114,15 @@ function getOdataString({ } const quotedSelectedItems = selectedItems.map((item) => - typeof item.value === 'string' || - entityFieldType === EEntityFieldType.STRING - ? `'${item.value}'` - : item.value + entityFieldType === EEntityFieldType.INTEGER + ? Number(item.value) + : `'${item.value}'` ); - if (entityFieldType === EEntityFieldType.COLLECTION) { + if ( + entityFieldType === EEntityFieldType.COLLECTION || + entityFieldType === EEntityFieldType.ARRAY + ) { return `${id}/any(x:${quotedSelectedItems .map((value) => `(x ${exclude ? 'ne' : 'eq'} ${value})`) .join(exclude ? ' and ' : ' or ')})`; diff --git a/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/utils/types.ts b/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/utils/types.ts index a9d98d24341066..bf14daf1e4366b 100644 --- a/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/utils/types.ts +++ b/modules/apps/frontend-data-set/frontend-data-set-web/src/main/resources/META-INF/resources/management_bar/controls/filters/utils/types.ts @@ -4,8 +4,10 @@ */ export enum EEntityFieldType { + ARRAY = 'array', COLLECTION = 'collection', DATE = 'date', DATE_TIME = 'date-time', + INTEGER = 'integer', STRING = 'string', } diff --git a/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/dto/v1_0/converter/ObjectEntryDTOConverter.java b/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/dto/v1_0/converter/ObjectEntryDTOConverter.java index cec73a59454157..57f316a5b89662 100644 --- a/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/dto/v1_0/converter/ObjectEntryDTOConverter.java +++ b/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/dto/v1_0/converter/ObjectEntryDTOConverter.java @@ -1308,6 +1308,32 @@ else if (Objects.equals( () -> _getValue( dtoConverterContext, objectDefinition, objectEntry, objectField, finalSerializable)); + + if (objectField.compareBusinessType( + ObjectFieldConstants.BUSINESS_TYPE_PICKLIST)) { + + String keyFieldName = objectFieldName + "Key"; + + unsafeSuppliers.put(keyFieldName, () -> finalSerializable); + } + else if (objectField.compareBusinessType( + ObjectFieldConstants. + BUSINESS_TYPE_MULTISELECT_PICKLIST)) { + + String keyFieldName = objectFieldName + "Key"; + + unsafeSuppliers.put( + keyFieldName, + () -> { + if (Validator.isNull(finalSerializable)) { + return null; + } + + return StringUtil.split( + (String)finalSerializable, + StringPool.COMMA_AND_SPACE); + }); + } } } diff --git a/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/odata/entity/v1_0/ObjectEntryEntityModel.java b/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/odata/entity/v1_0/ObjectEntryEntityModel.java index 5885b7560b7860..3a65b061acd487 100644 --- a/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/odata/entity/v1_0/ObjectEntryEntityModel.java +++ b/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/odata/entity/v1_0/ObjectEntryEntityModel.java @@ -19,6 +19,7 @@ import com.liferay.petra.string.StringPool; import com.liferay.portal.kernel.search.Field; import com.liferay.portal.kernel.util.HashMapBuilder; +import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.SetUtil; import com.liferay.portal.odata.entity.BooleanEntityField; import com.liferay.portal.odata.entity.CollectionEntityField; @@ -89,7 +90,7 @@ private ComplexEntityField _getComplexEntityField( relatedObjectDefinition.getName()); } - private EntityField _getEntityField(ObjectField objectField) { + private List _getEntityField(ObjectField objectField) { if (_unsupportedBusinessTypes.contains(objectField.getBusinessType())) { return null; } @@ -98,17 +99,25 @@ private EntityField _getEntityField(ObjectField objectField) { objectField.getBusinessType(), ObjectFieldConstants.BUSINESS_TYPE_DATE_TIME)) { - return new DateTimeEntityField( - objectField.getName(), locale -> objectField.getName(), - locale -> objectField.getName()); + return ListUtil.fromArray( + new DateTimeEntityField( + objectField.getName(), locale -> objectField.getName(), + locale -> objectField.getName())); } else if (Objects.equals( objectField.getBusinessType(), ObjectFieldConstants.BUSINESS_TYPE_MULTISELECT_PICKLIST)) { - return new CollectionEntityField( + // TODO Do this also for single select picklist? + + return ListUtil.fromArray( + new CollectionEntityField( + new StringEntityField( + objectField.getName(), + locale -> objectField.getName())), new StringEntityField( - objectField.getName(), locale -> objectField.getName())); + objectField.getName() + "Key", + locale -> objectField.getName())); } if (Objects.equals( @@ -117,33 +126,51 @@ else if (Objects.equals( Objects.equals( objectField.getDBType(), ObjectFieldConstants.DB_TYPE_DOUBLE)) { - return new DoubleEntityField( - objectField.getName(), locale -> objectField.getName()); + return ListUtil.fromArray( + new DoubleEntityField( + objectField.getName(), locale -> objectField.getName())); } else if (Objects.equals( objectField.getDBType(), ObjectFieldConstants.DB_TYPE_BOOLEAN)) { - return new BooleanEntityField( - objectField.getName(), locale -> objectField.getName()); + return ListUtil.fromArray( + new BooleanEntityField( + objectField.getName(), locale -> objectField.getName())); } else if (Objects.equals( objectField.getDBType(), ObjectFieldConstants.DB_TYPE_CLOB) || - Objects.equals( + (Objects.equals( objectField.getDBType(), - ObjectFieldConstants.DB_TYPE_STRING)) { + ObjectFieldConstants.DB_TYPE_STRING) && + !Objects.equals( + objectField.getBusinessType(), + ObjectFieldConstants.BUSINESS_TYPE_PICKLIST))) { - return new StringEntityField( - objectField.getName(), locale -> objectField.getName()); + return ListUtil.fromArray( + new StringEntityField( + objectField.getName(), locale -> objectField.getName())); + } + else if (Objects.equals( + objectField.getBusinessType(), + ObjectFieldConstants.BUSINESS_TYPE_PICKLIST)) { + + return ListUtil.fromArray( + new StringEntityField( + objectField.getName(), locale -> objectField.getName()), + new StringEntityField( + objectField.getName() + "Key", + locale -> objectField.getName())); } else if (Objects.equals( objectField.getDBType(), ObjectFieldConstants.DB_TYPE_DATE)) { - return new DateEntityField( - objectField.getName(), locale -> objectField.getName(), - locale -> objectField.getName()); + return ListUtil.fromArray( + new DateEntityField( + objectField.getName(), locale -> objectField.getName(), + locale -> objectField.getName())); } else if (Objects.equals( objectField.getDBType(), @@ -152,8 +179,9 @@ else if (Objects.equals( objectField.getDBType(), ObjectFieldConstants.DB_TYPE_LONG)) { - return new IntegerEntityField( - objectField.getName(), locale -> objectField.getName()); + return ListUtil.fromArray( + new IntegerEntityField( + objectField.getName(), locale -> objectField.getName())); } throw new BadRequestException( @@ -261,11 +289,12 @@ private Map _getStringEntityFieldsMap( objectField.getRelationshipType(), ObjectRelationshipConstants.TYPE_ONE_TO_MANY)) { - EntityField entityField = _getEntityField(objectField); + List entityFields = _getEntityField(objectField); - if (entityField != null) { - entityFieldsMap.putIfAbsent( - objectField.getName(), entityField); + if (entityFields != null) { + entityFields.forEach( + entityField -> entityFieldsMap.putIfAbsent( + entityField.getName(), entityField)); } continue; diff --git a/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/openapi/v1_0/ObjectEntryOpenAPIResourceImpl.java b/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/openapi/v1_0/ObjectEntryOpenAPIResourceImpl.java index d48306091fac9d..86b09a348e4091 100644 --- a/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/openapi/v1_0/ObjectEntryOpenAPIResourceImpl.java +++ b/modules/apps/object/object-rest-impl/src/main/java/com/liferay/object/rest/internal/openapi/v1_0/ObjectEntryOpenAPIResourceImpl.java @@ -286,7 +286,20 @@ else if (Objects.equals( "name", String.class.getSimpleName()))); dtoProperty.setRequired(objectField.isRequired()); - return ListUtil.fromArray(dtoProperty); + return ListUtil.fromArray( + dtoProperty, + new DTOProperty( + HashMapBuilder.put( + "x-parent-map", "properties" + ).build(), + objectField.getName() + "Key", + String.class.getSimpleName()) { + + { + setReadOnly(true); + setRequired(objectField.isRequired()); + } + }); } else if (Objects.equals( objectField.getBusinessType(),