diff --git a/opencti-platform/opencti-front/src/private/components/data/ToolBar.jsx b/opencti-platform/opencti-front/src/private/components/data/ToolBar.jsx index 1e1f95b75395..38d4fad7fc77 100644 --- a/opencti-platform/opencti-front/src/private/components/data/ToolBar.jsx +++ b/opencti-platform/opencti-front/src/private/components/data/ToolBar.jsx @@ -1337,7 +1337,7 @@ class ToolBar extends Component { const currentMap = schema.filterKeysSchema.get(entityType); currentMap?.forEach((value, key) => filterKeysMap.set(key, value)); }); - const availableFilterKeys = Array.from(filterKeysMap.keys() ?? []).concat(['entity_type']); + const availableFilterKeys = Array.from(filterKeysMap.keys()).concat(['entity_type']); // endregion return ( , // map in construction - nestedAttributeDefinition: NestedObjectAttribute, // nested attribute to study + objectAttributeDefinition: ComplexAttributeWithMappings, // object attribute with mappings types: string[], // entity types to apply ) => { - const { mappings } = nestedAttributeDefinition; + const { mappings } = objectAttributeDefinition; mappings.forEach((mappingAttributeDefinition) => { if (mappingAttributeDefinition.isFilterable) { - if (mappingAttributeDefinition.type === 'object' && ['nested', 'standard'].includes(mappingAttributeDefinition.format)) { // case 1: nested attribute - throw Error('A nested attribute can\'t contain a nested attribute'); // not supported for the moment - } else if (mappingAttributeDefinition.associatedFilterKeys) { // case 2: not nested attribute and associatedFilterKeys is set + if (mappingAttributeDefinition.type === 'object' && ['nested', 'standard'].includes(mappingAttributeDefinition.format)) { // case 1: object attribute with mappings + const composedMappingName = `${objectAttributeDefinition.name}.${mappingAttributeDefinition.name}`; + completeFilterDefinitionMapWithObjectAttributeWithMappings( + attributesMapWithFilterDefinition, + { ...mappingAttributeDefinition, name: composedMappingName } as ComplexAttributeWithMappings, + types + ); + } else if (mappingAttributeDefinition.associatedFilterKeys) { // case 2: attribute with no mappings and associatedFilterKeys is set // the keys to add are the ones in associatedFilterKeys mappingAttributeDefinition.associatedFilterKeys.forEach(({ key, label }) => { completeFilterDefinitionMapWithElement(attributesMapWithFilterDefinition, types, key, { ...mappingAttributeDefinition, name: key, label }, 'attribute'); }); - } else { // case 3: not nested attribute and the key to add is composed with the attribute name and the mapping attribute name - const composedMappingName = `${nestedAttributeDefinition.name}.${mappingAttributeDefinition.name}`; + } else { // case 3: attribute with no mappings and the key to add is composed with the attribute name and the mapping attribute name + const composedMappingName = `${objectAttributeDefinition.name}.${mappingAttributeDefinition.name}`; completeFilterDefinitionMapWithElement(attributesMapWithFilterDefinition, types, composedMappingName, { ...mappingAttributeDefinition, name: composedMappingName }, 'attribute'); } } @@ -172,8 +177,8 @@ const completeFilterDefinitionMapForType = ( attributesMap.forEach((attributeDefinition, attributeName) => { if (attributeDefinition.isFilterable) { // if it is filterable if (attributeDefinition.type === 'object' && ['nested', 'standard'].includes(attributeDefinition.format)) { // case 1.1: attribute with mappings - completeFilterDefinitionMapWithNestedAttribute(filterDefinitionMap, attributeDefinition as NestedObjectAttribute, types); - } else { // case 1.2: not nested attribute + completeFilterDefinitionMapWithObjectAttributeWithMappings(filterDefinitionMap, attributeDefinition as ComplexAttributeWithMappings, types); + } else { // case 1.2: attribute with no mappings completeFilterDefinitionMapWithElement(filterDefinitionMap, types, attributeName, attributeDefinition, 'attribute'); } } diff --git a/opencti-platform/opencti-graphql/src/modules/notification/notification.ts b/opencti-platform/opencti-graphql/src/modules/notification/notification.ts index da4bec2cecf1..5f8db7f1dc16 100644 --- a/opencti-platform/opencti-graphql/src/modules/notification/notification.ts +++ b/opencti-platform/opencti-graphql/src/modules/notification/notification.ts @@ -8,7 +8,7 @@ import { type StoreEntityNotification, type StoreEntityTrigger } from './notification-types'; -import { ABSTRACT_INTERNAL_OBJECT } from '../../schema/general'; +import { ABSTRACT_INTERNAL_OBJECT, ABSTRACT_STIX_CORE_OBJECT } from '../../schema/general'; import type { ModuleDefinition } from '../../schema/module'; import { registerDefinition } from '../../schema/module'; import { authorizedAuthorities, authorizedMembers } from '../../schema/attribute-definition'; @@ -81,9 +81,9 @@ const NOTIFICATION_DEFINITION: ModuleDefinition { // 'LZJD hash' for observables (not filterable) filterDefinition = filterKeysSchema.get(ABSTRACT_STIX_CYBER_OBSERVABLE)?.get('hashes.LZJD'); expect(filterDefinition).toBeUndefined(); // LZJD hash is not filterable + // 'operation' for notifications (mapping attribute in a mapping attribute) + filterDefinition = filterKeysSchema.get(ABSTRACT_STIX_CYBER_OBSERVABLE)?.get('notification_content.events.operation'); + expect(filterDefinition?.filterKey).toEqual('notification_content.events.operation'); + expect(filterDefinition?.type).toEqual('enum'); + expect(filterDefinition?.elementsForFilterValuesSearch.length).toEqual(3); // create, update, delete }); it('should construct correct filter definition for nested object attributes', () => { // 'fromId' for relationships