mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-25 06:28:22 +00:00
* fix: remove recursive extraction of nested fields for entityReference and entityReferenceList type custom properties * get displayName field along with other fields in /customProperties api * show display name instead of name for custom props * show display name instead of name for custom props * fix extension type and add tests * fix tests * fix data model tests --------- Co-authored-by: karanh37 <karanh37@gmail.com> Co-authored-by: Karan Hotchandani <33024356+karanh37@users.noreply.github.com>
This commit is contained in:
parent
94cf3e0fd6
commit
971225dbce
@ -18,7 +18,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.everit.json.schema.*;
|
||||
import org.everit.json.schema.ArraySchema;
|
||||
import org.everit.json.schema.BooleanSchema;
|
||||
import org.everit.json.schema.NullSchema;
|
||||
import org.everit.json.schema.NumberSchema;
|
||||
import org.everit.json.schema.ObjectSchema;
|
||||
import org.everit.json.schema.ReferenceSchema;
|
||||
import org.everit.json.schema.Schema;
|
||||
import org.everit.json.schema.StringSchema;
|
||||
import org.everit.json.schema.loader.SchemaClient;
|
||||
import org.everit.json.schema.loader.SchemaLoader;
|
||||
import org.json.JSONObject;
|
||||
@ -207,7 +214,7 @@ public class SchemaFieldExtractor {
|
||||
} else {
|
||||
String fieldType = mapSchemaTypeToSimpleType(fieldSchema);
|
||||
fieldTypesMap.putIfAbsent(
|
||||
fullFieldName, new FieldDefinition(fullFieldName, fieldType, null));
|
||||
fullFieldName, FieldDefinition.of(fullFieldName, fullFieldName, fieldType, null));
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added field '{}', Type: '{}'", fullFieldName, fieldType);
|
||||
// Recursively process nested objects or arrays
|
||||
@ -221,7 +228,8 @@ public class SchemaFieldExtractor {
|
||||
handleArraySchema(arraySchema, parentPath, fieldTypesMap, processingStack, processedFields);
|
||||
} else {
|
||||
String fieldType = mapSchemaTypeToSimpleType(schema);
|
||||
fieldTypesMap.putIfAbsent(parentPath, new FieldDefinition(parentPath, fieldType, null));
|
||||
fieldTypesMap.putIfAbsent(
|
||||
parentPath, FieldDefinition.of(parentPath, parentPath, fieldType, null));
|
||||
LOG.debug("Added field '{}', Type: '{}'", parentPath, fieldType);
|
||||
}
|
||||
} finally {
|
||||
@ -241,7 +249,7 @@ public class SchemaFieldExtractor {
|
||||
|
||||
if (referenceType != null) {
|
||||
fieldTypesMap.putIfAbsent(
|
||||
fullFieldName, new FieldDefinition(fullFieldName, referenceType, null));
|
||||
fullFieldName, FieldDefinition.of(fullFieldName, fullFieldName, referenceType, null));
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added field '{}', Type: '{}'", fullFieldName, referenceType);
|
||||
if (referenceType.startsWith("array<") && referenceType.endsWith(">")) {
|
||||
@ -257,7 +265,8 @@ public class SchemaFieldExtractor {
|
||||
referredSchema, fullFieldName, fieldTypesMap, processingStack, processedFields);
|
||||
}
|
||||
} else {
|
||||
fieldTypesMap.putIfAbsent(fullFieldName, new FieldDefinition(fullFieldName, "object", null));
|
||||
fieldTypesMap.putIfAbsent(
|
||||
fullFieldName, FieldDefinition.of(fullFieldName, fullFieldName, "object", null));
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added field '{}', Type: 'object'", fullFieldName);
|
||||
extractFieldsFromSchema(
|
||||
@ -285,7 +294,7 @@ public class SchemaFieldExtractor {
|
||||
if (itemsReferenceType != null) {
|
||||
String arrayFieldType = "array<" + itemsReferenceType + ">";
|
||||
fieldTypesMap.putIfAbsent(
|
||||
fullFieldName, new FieldDefinition(fullFieldName, arrayFieldType, null));
|
||||
fullFieldName, FieldDefinition.of(fullFieldName, fullFieldName, arrayFieldType, null));
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added field '{}', Type: '{}'", fullFieldName, arrayFieldType);
|
||||
Schema referredItemsSchema = itemsReferenceSchema.getReferredSchema();
|
||||
@ -296,7 +305,8 @@ public class SchemaFieldExtractor {
|
||||
}
|
||||
String arrayType = mapSchemaTypeToSimpleType(itemsSchema);
|
||||
fieldTypesMap.putIfAbsent(
|
||||
fullFieldName, new FieldDefinition(fullFieldName, "array<" + arrayType + ">", null));
|
||||
fullFieldName,
|
||||
FieldDefinition.of(fullFieldName, fullFieldName, "array<" + arrayType + ">", null));
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added field '{}', Type: 'array<{}>'", fullFieldName, arrayType);
|
||||
|
||||
@ -321,49 +331,31 @@ public class SchemaFieldExtractor {
|
||||
String propertyName = customProperty.getName();
|
||||
String propertyType = customProperty.getPropertyType().getName();
|
||||
String fullFieldName = propertyName; // No parent path for custom properties
|
||||
|
||||
String displayName = customProperty.getDisplayName();
|
||||
LOG.debug("Processing custom property '{}'", fullFieldName);
|
||||
|
||||
Object customPropertyConfigObj = customProperty.getCustomPropertyConfig();
|
||||
|
||||
if (isEntityReferenceList(propertyType)) {
|
||||
String referenceType = "array<entityReference>";
|
||||
FieldDefinition referenceFieldDefinition =
|
||||
new FieldDefinition(fullFieldName, referenceType, customPropertyConfigObj);
|
||||
fieldTypesMap.putIfAbsent(fullFieldName, referenceFieldDefinition);
|
||||
FieldDefinition fieldDef =
|
||||
FieldDefinition.of(fullFieldName, displayName, referenceType, customPropertyConfigObj);
|
||||
fieldTypesMap.putIfAbsent(fullFieldName, fieldDef);
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added custom property '{}', Type: '{}'", fullFieldName, referenceType);
|
||||
|
||||
Schema itemSchema = resolveSchemaByType("entityReference", schemaUri, schemaClient);
|
||||
if (itemSchema != null) {
|
||||
extractFieldsFromSchema(
|
||||
itemSchema, fullFieldName, fieldTypesMap, processingStack, processedFields);
|
||||
} else {
|
||||
LOG.warn(
|
||||
"Schema for type 'entityReference' not found. Skipping nested field extraction for '{}'.",
|
||||
fullFieldName);
|
||||
}
|
||||
} else if (isEntityReference(propertyType)) {
|
||||
String referenceType = "entityReference";
|
||||
FieldDefinition referenceFieldDefinition =
|
||||
new FieldDefinition(fullFieldName, referenceType, customPropertyConfigObj);
|
||||
fieldTypesMap.putIfAbsent(fullFieldName, referenceFieldDefinition);
|
||||
FieldDefinition fieldDef =
|
||||
FieldDefinition.of(fullFieldName, displayName, referenceType, customPropertyConfigObj);
|
||||
fieldTypesMap.putIfAbsent(fullFieldName, fieldDef);
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added custom property '{}', Type: '{}'", fullFieldName, referenceType);
|
||||
|
||||
Schema referredSchema = resolveSchemaByType("entityReference", schemaUri, schemaClient);
|
||||
if (referredSchema != null) {
|
||||
extractFieldsFromSchema(
|
||||
referredSchema, fullFieldName, fieldTypesMap, processingStack, processedFields);
|
||||
} else {
|
||||
LOG.warn(
|
||||
"Schema for type 'entityReference' not found. Skipping nested field extraction for '{}'.",
|
||||
fullFieldName);
|
||||
}
|
||||
} else {
|
||||
FieldDefinition entityFieldDefinition =
|
||||
new FieldDefinition(fullFieldName, propertyType, customPropertyConfigObj);
|
||||
fieldTypesMap.putIfAbsent(fullFieldName, entityFieldDefinition);
|
||||
FieldDefinition fieldDef =
|
||||
FieldDefinition.of(fullFieldName, displayName, propertyType, customPropertyConfigObj);
|
||||
fieldTypesMap.putIfAbsent(fullFieldName, fieldDef);
|
||||
processedFields.add(fullFieldName);
|
||||
LOG.debug("Added custom property '{}', Type: '{}'", fullFieldName, propertyType);
|
||||
}
|
||||
@ -375,8 +367,11 @@ public class SchemaFieldExtractor {
|
||||
for (Map.Entry<String, FieldDefinition> entry : fieldTypesMap.entrySet()) {
|
||||
FieldDefinition fieldDef = entry.getValue();
|
||||
fieldsList.add(
|
||||
new FieldDefinition(
|
||||
fieldDef.getName(), fieldDef.getType(), fieldDef.getCustomPropertyConfig()));
|
||||
FieldDefinition.of(
|
||||
fieldDef.getName(),
|
||||
fieldDef.getDisplayName(),
|
||||
fieldDef.getType(),
|
||||
fieldDef.getCustomPropertyConfig()));
|
||||
}
|
||||
return fieldsList;
|
||||
}
|
||||
@ -638,13 +633,28 @@ public class SchemaFieldExtractor {
|
||||
@lombok.Setter
|
||||
public static class FieldDefinition {
|
||||
private String name;
|
||||
private String displayName;
|
||||
private String type;
|
||||
private Object customPropertyConfig;
|
||||
|
||||
public FieldDefinition(String name, String type, Object customPropertyConfig) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.type = type;
|
||||
this.customPropertyConfig = customPropertyConfig;
|
||||
}
|
||||
|
||||
public FieldDefinition(
|
||||
String name, String displayName, String type, Object customPropertyConfig) {
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.type = type;
|
||||
this.customPropertyConfig = customPropertyConfig;
|
||||
}
|
||||
|
||||
public static FieldDefinition of(
|
||||
String name, String displayName, String type, Object customPropertyConfig) {
|
||||
return new FieldDefinition(name, displayName, type, customPropertyConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,7 +351,7 @@ export const CUSTOM_PROPERTIES_ENTITIES = {
|
||||
},
|
||||
},
|
||||
entity_dashboardDataModel: {
|
||||
name: 'dataModel',
|
||||
name: 'dashboardDataModel',
|
||||
description: 'This is Data Model custom property',
|
||||
integerValue: '23',
|
||||
stringValue: 'This is string propery',
|
||||
|
||||
@ -100,6 +100,12 @@ test.describe('Advanced Search Custom Property', () => {
|
||||
'Custom Properties'
|
||||
);
|
||||
|
||||
await selectOption(
|
||||
page,
|
||||
ruleLocator.locator('.rule--field .ant-select'),
|
||||
'Table'
|
||||
);
|
||||
|
||||
// Perform click on custom property type to filter
|
||||
await selectOption(
|
||||
page,
|
||||
|
||||
@ -15,6 +15,7 @@ import { CUSTOM_PROPERTIES_ENTITIES } from '../../../constant/customProperty';
|
||||
import { GlobalSettingOptions } from '../../../constant/settings';
|
||||
import { SidebarItem } from '../../../constant/sidebar';
|
||||
import { DashboardClass } from '../../../support/entity/DashboardClass';
|
||||
import { selectOption } from '../../../utils/advancedSearch';
|
||||
import { createNewPage, redirectToHomePage, uuid } from '../../../utils/common';
|
||||
import {
|
||||
addCustomPropertiesForEntity,
|
||||
@ -122,8 +123,16 @@ test('CustomProperty Dashboard Filter', async ({ page }) => {
|
||||
.getByText('Owner')
|
||||
.click();
|
||||
|
||||
const ruleLocator = page.locator('.rule').nth(0);
|
||||
|
||||
await page.getByTitle('Custom Properties').click();
|
||||
|
||||
await selectOption(
|
||||
page,
|
||||
ruleLocator.locator('.rule--field .ant-select'),
|
||||
'Dashboard'
|
||||
);
|
||||
|
||||
// Select Custom Property Field when we want filter
|
||||
await page
|
||||
.locator(
|
||||
@ -145,13 +154,15 @@ test('CustomProperty Dashboard Filter', async ({ page }) => {
|
||||
|
||||
// Validate if filter dashboard appeared
|
||||
|
||||
expect(page.getByTestId('advance-search-filter-text')).toContainText(
|
||||
`extension.${propertyName} = '${propertyValue}'`
|
||||
await expect(
|
||||
page.getByTestId('advance-search-filter-text')
|
||||
).toContainText(
|
||||
`extension.dashboard.${propertyName} = '${propertyValue}'`
|
||||
);
|
||||
|
||||
expect(page.getByTestId('entity-header-display-name')).toContainText(
|
||||
dashboardEntity.entity.displayName
|
||||
);
|
||||
await expect(
|
||||
page.getByTestId('entity-header-display-name')
|
||||
).toContainText(dashboardEntity.entity.displayName);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
addCustomPropertiesForEntity,
|
||||
deleteCreatedProperty,
|
||||
editCreatedProperty,
|
||||
verifyCustomPropertyInAdvancedSearch,
|
||||
} from '../../utils/customProperty';
|
||||
import { settingClick, SettingOptionsType } from '../../utils/sidebar';
|
||||
|
||||
@ -65,6 +66,18 @@ test.describe('Custom properties without custom property config', () => {
|
||||
|
||||
await editCreatedProperty(page, propertyName);
|
||||
|
||||
await verifyCustomPropertyInAdvancedSearch(
|
||||
page,
|
||||
propertyName.toUpperCase(), // displayName is in uppercase
|
||||
entity.name.charAt(0).toUpperCase() + entity.name.slice(1)
|
||||
);
|
||||
|
||||
await settingClick(
|
||||
page,
|
||||
entity.entityApiType as SettingOptionsType,
|
||||
true
|
||||
);
|
||||
|
||||
await deleteCreatedProperty(page, propertyName);
|
||||
});
|
||||
});
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
addCustomPropertiesForEntity,
|
||||
deleteCreatedProperty,
|
||||
editCreatedProperty,
|
||||
verifyCustomPropertyInAdvancedSearch,
|
||||
} from '../../utils/customProperty';
|
||||
import { settingClick, SettingOptionsType } from '../../utils/sidebar';
|
||||
|
||||
@ -51,6 +52,18 @@ test.describe('Custom properties with custom property config', () => {
|
||||
|
||||
await editCreatedProperty(page, propertyName, 'Enum');
|
||||
|
||||
await verifyCustomPropertyInAdvancedSearch(
|
||||
page,
|
||||
propertyName.toUpperCase(), // displayName is in uppercase
|
||||
entity.name.charAt(0).toUpperCase() + entity.name.slice(1)
|
||||
);
|
||||
|
||||
await settingClick(
|
||||
page,
|
||||
entity.entityApiType as SettingOptionsType,
|
||||
true
|
||||
);
|
||||
|
||||
await deleteCreatedProperty(page, propertyName);
|
||||
});
|
||||
});
|
||||
@ -79,6 +92,18 @@ test.describe('Custom properties with custom property config', () => {
|
||||
|
||||
await editCreatedProperty(page, propertyName, 'Table');
|
||||
|
||||
await verifyCustomPropertyInAdvancedSearch(
|
||||
page,
|
||||
propertyName.toUpperCase(), // displayName is in uppercase
|
||||
entity.name.charAt(0).toUpperCase() + entity.name.slice(1)
|
||||
);
|
||||
|
||||
await settingClick(
|
||||
page,
|
||||
entity.entityApiType as SettingOptionsType,
|
||||
true
|
||||
);
|
||||
|
||||
await deleteCreatedProperty(page, propertyName);
|
||||
});
|
||||
});
|
||||
@ -111,6 +136,18 @@ test.describe('Custom properties with custom property config', () => {
|
||||
|
||||
await editCreatedProperty(page, propertyName, 'Entity Reference');
|
||||
|
||||
await verifyCustomPropertyInAdvancedSearch(
|
||||
page,
|
||||
propertyName.toUpperCase(), // displayName is in uppercase
|
||||
entity.name.charAt(0).toUpperCase() + entity.name.slice(1)
|
||||
);
|
||||
|
||||
await settingClick(
|
||||
page,
|
||||
entity.entityApiType as SettingOptionsType,
|
||||
true
|
||||
);
|
||||
|
||||
await deleteCreatedProperty(page, propertyName);
|
||||
});
|
||||
});
|
||||
@ -148,6 +185,18 @@ test.describe('Custom properties with custom property config', () => {
|
||||
'Entity Reference List'
|
||||
);
|
||||
|
||||
await verifyCustomPropertyInAdvancedSearch(
|
||||
page,
|
||||
propertyName.toUpperCase(), // displayName is in uppercase
|
||||
entity.name.charAt(0).toUpperCase() + entity.name.slice(1)
|
||||
);
|
||||
|
||||
await settingClick(
|
||||
page,
|
||||
entity.entityApiType as SettingOptionsType,
|
||||
true
|
||||
);
|
||||
|
||||
await deleteCreatedProperty(page, propertyName);
|
||||
});
|
||||
});
|
||||
@ -205,6 +254,18 @@ test.describe('Custom properties with custom property config', () => {
|
||||
|
||||
await editCreatedProperty(page, propertyName);
|
||||
|
||||
await verifyCustomPropertyInAdvancedSearch(
|
||||
page,
|
||||
propertyName.toUpperCase(), // displayName is in uppercase
|
||||
entity.name.charAt(0).toUpperCase() + entity.name.slice(1)
|
||||
);
|
||||
|
||||
await settingClick(
|
||||
page,
|
||||
entity.entityApiType as SettingOptionsType,
|
||||
true
|
||||
);
|
||||
|
||||
await deleteCreatedProperty(page, propertyName);
|
||||
});
|
||||
});
|
||||
@ -235,6 +296,18 @@ test.describe('Custom properties with custom property config', () => {
|
||||
|
||||
await editCreatedProperty(page, propertyName);
|
||||
|
||||
await verifyCustomPropertyInAdvancedSearch(
|
||||
page,
|
||||
propertyName.toUpperCase(), // displayName is in uppercase
|
||||
entity.name.charAt(0).toUpperCase() + entity.name.slice(1)
|
||||
);
|
||||
|
||||
await settingClick(
|
||||
page,
|
||||
entity.entityApiType as SettingOptionsType,
|
||||
true
|
||||
);
|
||||
|
||||
await deleteCreatedProperty(page, propertyName);
|
||||
});
|
||||
});
|
||||
|
||||
@ -16,17 +16,20 @@ import {
|
||||
CUSTOM_PROPERTY_NAME_VALIDATION_ERROR,
|
||||
ENTITY_REFERENCE_PROPERTIES,
|
||||
} from '../constant/customProperty';
|
||||
import { SidebarItem } from '../constant/sidebar';
|
||||
import {
|
||||
EntityTypeEndpoint,
|
||||
ENTITY_PATH,
|
||||
} from '../support/entity/Entity.interface';
|
||||
import { UserClass } from '../support/user/UserClass';
|
||||
import { selectOption, showAdvancedSearchDialog } from './advancedSearch';
|
||||
import {
|
||||
clickOutside,
|
||||
descriptionBox,
|
||||
descriptionBoxReadOnly,
|
||||
uuid,
|
||||
} from './common';
|
||||
import { sidebarClick } from './sidebar';
|
||||
|
||||
export enum CustomPropertyType {
|
||||
STRING = 'String',
|
||||
@ -732,7 +735,7 @@ export const editCreatedProperty = async (
|
||||
|
||||
// displayName
|
||||
await page.fill('[data-testid="display-name"]', '');
|
||||
await page.fill('[data-testid="display-name"]', propertyName);
|
||||
await page.fill('[data-testid="display-name"]', propertyName.toUpperCase());
|
||||
|
||||
await page.locator(descriptionBox).fill('');
|
||||
await page.locator(descriptionBox).fill('This is new description');
|
||||
@ -807,3 +810,38 @@ export const deleteCreatedProperty = async (
|
||||
|
||||
await page.locator('[data-testid="save-button"]').click();
|
||||
};
|
||||
|
||||
export const verifyCustomPropertyInAdvancedSearch = async (
|
||||
page: Page,
|
||||
propertyName: string,
|
||||
entityType: string
|
||||
) => {
|
||||
await sidebarClick(page, SidebarItem.EXPLORE);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Open advanced search dialog
|
||||
await showAdvancedSearchDialog(page);
|
||||
|
||||
const ruleLocator = page.locator('.rule').nth(0);
|
||||
|
||||
// Select "Custom Properties" from the field dropdown
|
||||
await selectOption(
|
||||
page,
|
||||
ruleLocator.locator('.rule--field .ant-select'),
|
||||
'Custom Properties'
|
||||
);
|
||||
|
||||
await selectOption(
|
||||
page,
|
||||
ruleLocator.locator('.rule--field .ant-select'),
|
||||
entityType
|
||||
);
|
||||
|
||||
await selectOption(
|
||||
page,
|
||||
ruleLocator.locator('.rule--field .ant-select'),
|
||||
propertyName
|
||||
);
|
||||
|
||||
await page.getByTestId('cancel-btn').click();
|
||||
};
|
||||
|
||||
@ -224,18 +224,31 @@ export const AdvanceSearchProvider = ({
|
||||
try {
|
||||
const res = await getAllCustomProperties();
|
||||
|
||||
Object.entries(res).forEach(([_, fields]) => {
|
||||
Object.entries(res).forEach(([entityType, fields]) => {
|
||||
if (Array.isArray(fields) && fields.length > 0) {
|
||||
// Create nested subfields for each entity type (e.g., table, database, etc.)
|
||||
const entitySubfields: Record<string, Field> = {};
|
||||
|
||||
fields.forEach((field) => {
|
||||
if (field.name && field.type) {
|
||||
const { subfieldsKey, dataObject } =
|
||||
advancedSearchClassBase.getCustomPropertiesSubFields(field);
|
||||
subfields[subfieldsKey] = {
|
||||
|
||||
entitySubfields[subfieldsKey] = {
|
||||
...dataObject,
|
||||
valueSources: dataObject.valueSources as ValueSource[],
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Only create the entity type field if it has custom properties
|
||||
if (!isEmpty(entitySubfields)) {
|
||||
subfields[entityType] = {
|
||||
label: entityType.charAt(0).toUpperCase() + entityType.slice(1),
|
||||
type: '!group',
|
||||
subfields: entitySubfields,
|
||||
} as Field;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
.group.rule_group {
|
||||
border: none !important;
|
||||
padding: 0;
|
||||
|
||||
.group--children {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
@ -24,12 +25,20 @@
|
||||
|
||||
.group--field {
|
||||
width: 180px;
|
||||
|
||||
.ant-select {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: normal;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.rule_group {
|
||||
.group--field {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ import {
|
||||
getCustomPropertyAdvanceSearchEnumOptions,
|
||||
renderAdvanceSearchButtons,
|
||||
} from './AdvancedSearchUtils';
|
||||
import { getEntityName } from './EntityUtils';
|
||||
import { getCombinedQueryFilterObject } from './ExplorePage/ExplorePageUtils';
|
||||
import { renderQueryBuilderFilterButtons } from './QueryBuilderUtils';
|
||||
import { parseBucketsData } from './SearchUtils';
|
||||
@ -955,76 +956,77 @@ class AdvancedSearchClassBase {
|
||||
};
|
||||
|
||||
public getCustomPropertiesSubFields(field: CustomPropertySummary) {
|
||||
{
|
||||
switch (field.type) {
|
||||
case 'array<entityReference>':
|
||||
case 'entityReference':
|
||||
return {
|
||||
subfieldsKey: field.name + `.displayName`,
|
||||
dataObject: {
|
||||
type: 'select',
|
||||
label: field.name,
|
||||
fieldSettings: {
|
||||
asyncFetch: this.autocomplete({
|
||||
searchIndex: (
|
||||
(field.customPropertyConfig?.config ?? []) as string[]
|
||||
).join(',') as SearchIndex,
|
||||
entityField: EntityFields.DISPLAY_NAME_KEYWORD,
|
||||
}),
|
||||
useAsyncSearch: true,
|
||||
},
|
||||
const label = getEntityName(field);
|
||||
switch (field.type) {
|
||||
case 'array<entityReference>':
|
||||
case 'entityReference':
|
||||
return {
|
||||
subfieldsKey: field.name + `.displayName`,
|
||||
dataObject: {
|
||||
type: 'select',
|
||||
label,
|
||||
fieldSettings: {
|
||||
asyncFetch: this.autocomplete({
|
||||
searchIndex: (
|
||||
(field.customPropertyConfig?.config ?? []) as string[]
|
||||
).join(',') as SearchIndex,
|
||||
entityField: EntityFields.DISPLAY_NAME_KEYWORD,
|
||||
}),
|
||||
useAsyncSearch: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
case 'enum':
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'select',
|
||||
operators: LIST_VALUE_OPERATORS,
|
||||
fieldSettings: {
|
||||
listValues: getCustomPropertyAdvanceSearchEnumOptions(
|
||||
(
|
||||
field.customPropertyConfig
|
||||
?.config as CustomPropertyEnumConfig
|
||||
).values
|
||||
),
|
||||
},
|
||||
case 'enum':
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'select',
|
||||
label,
|
||||
operators: LIST_VALUE_OPERATORS,
|
||||
fieldSettings: {
|
||||
listValues: getCustomPropertyAdvanceSearchEnumOptions(
|
||||
(field.customPropertyConfig?.config as CustomPropertyEnumConfig)
|
||||
.values
|
||||
),
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
case 'date-cp': {
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'date',
|
||||
operators: RANGE_FIELD_OPERATORS,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
case 'timestamp':
|
||||
case 'integer':
|
||||
case 'number': {
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'number',
|
||||
operators: RANGE_FIELD_OPERATORS,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'text',
|
||||
valueSources: ['value'],
|
||||
operators: TEXT_FIELD_OPERATORS,
|
||||
},
|
||||
};
|
||||
case 'date-cp': {
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'date',
|
||||
label,
|
||||
operators: RANGE_FIELD_OPERATORS,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
case 'timestamp':
|
||||
case 'integer':
|
||||
case 'number': {
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'number',
|
||||
label,
|
||||
operators: RANGE_FIELD_OPERATORS,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return {
|
||||
subfieldsKey: field.name,
|
||||
dataObject: {
|
||||
type: 'text',
|
||||
label,
|
||||
valueSources: ['value'],
|
||||
operators: TEXT_FIELD_OPERATORS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,6 +244,19 @@ function buildParameters(queryType, value, operator, fieldName, config) {
|
||||
*/
|
||||
function buildEsRule(fieldName, value, operator, config, valueSrc) {
|
||||
if (!fieldName || !operator || value == undefined) return undefined; // rule is not fully entered
|
||||
|
||||
// Check if field has custom elasticsearch field mapping or handle extension fields
|
||||
let actualFieldName = fieldName;
|
||||
let isNestedExtensionField = false;
|
||||
let entityType = null;
|
||||
|
||||
if (fieldName.startsWith('extension.') && fieldName.split('.').length >= 3) {
|
||||
const parts = fieldName.split('.');
|
||||
entityType = parts[1];
|
||||
actualFieldName = `${parts[0]}.${parts.slice(2).join('.')}`;
|
||||
isNestedExtensionField = true;
|
||||
}
|
||||
|
||||
let op = operator;
|
||||
let opConfig = config.operators[op];
|
||||
if (!opConfig) return undefined; // unknown operator
|
||||
@ -286,15 +299,17 @@ function buildEsRule(fieldName, value, operator, config, valueSrc) {
|
||||
queryType,
|
||||
value,
|
||||
op,
|
||||
fieldName,
|
||||
actualFieldName,
|
||||
config
|
||||
);
|
||||
} else {
|
||||
parameters = buildParameters(queryType, value, op, fieldName, config);
|
||||
parameters = buildParameters(queryType, value, op, actualFieldName, config);
|
||||
}
|
||||
|
||||
// Build the main query
|
||||
let mainQuery;
|
||||
if (not) {
|
||||
return {
|
||||
mainQuery = {
|
||||
bool: {
|
||||
must_not: {
|
||||
[queryType]: { ...parameters },
|
||||
@ -302,10 +317,28 @@ function buildEsRule(fieldName, value, operator, config, valueSrc) {
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
mainQuery = {
|
||||
[queryType]: { ...parameters },
|
||||
};
|
||||
}
|
||||
|
||||
// For nested extension fields, combine with entityType filter
|
||||
if (isNestedExtensionField && entityType) {
|
||||
return {
|
||||
bool: {
|
||||
must: [
|
||||
mainQuery,
|
||||
{
|
||||
term: {
|
||||
entityType: entityType,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return mainQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user