diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java index 71dae84dbe2..b0e60c33779 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java @@ -1518,12 +1518,6 @@ public abstract class EntityRepository { + undefinedColumns); } - if (fieldValue.get("rows").size() > tableConfig.getRowCount()) { - throw new IllegalArgumentException( - "Number of rows should be less than or equal to the expected row count " - + tableConfig.getRowCount()); - } - Set rowFieldNames = new HashSet<>(); fieldValue.get("rows").forEach(row -> row.fieldNames().forEachRemaining(rowFieldNames::add)); diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TypeRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TypeRepository.java index b8793ac7600..f82772dc36f 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TypeRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TypeRepository.java @@ -23,7 +23,6 @@ import static org.openmetadata.service.util.EntityUtil.customFieldMatch; import static org.openmetadata.service.util.EntityUtil.getCustomField; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashSet; @@ -243,12 +242,6 @@ public class TypeRepository extends EntityRepository { JsonNode configNode = JsonUtils.valueToTree(config.getConfig()); TableConfig tableConfig = JsonUtils.convertValue(config.getConfig(), TableConfig.class); - // rowCount is optional, if not present set it to the default value - if (!configNode.has("rowCount")) { - ((ObjectNode) configNode).put("rowCount", tableConfig.getRowCount()); - config.setConfig(configNode); - } - List columns = new ArrayList<>(); configNode.path("columns").forEach(node -> columns.add(node.asText())); Set uniqueColumns = new HashSet<>(columns); diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/metadata/TypeResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/metadata/TypeResourceTest.java index ebec8157c80..591e3ee5e75 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/metadata/TypeResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/metadata/TypeResourceTest.java @@ -342,26 +342,6 @@ public class TypeResourceTest extends EntityResourceTest { + " and " + tableConfig.getMaxColumns()); - tableTypeFieldA.setCustomPropertyConfig( - new CustomPropertyConfig() - .withConfig( - new TableConfig() - .withColumns(Set.of("column-1", "column-2", "column-3")) - .withRowCount(200))); - ChangeDescription change2 = getChangeDescription(databaseEntity, MINOR_UPDATE); - Type databaseEntity2 = databaseEntity; - assertResponseContains( - () -> - addCustomPropertyAndCheck( - databaseEntity2.getId(), - tableTypeFieldA, - ADMIN_AUTH_HEADERS, - MINOR_UPDATE, - change2), - Status.BAD_REQUEST, - "Custom Property table has invalid value rowCount must be less than or equal to " - + tableConfig.getMaxRows()); - ObjectMapper mapper = new ObjectMapper(); ObjectNode tableConfigJson = mapper.createObjectNode(); ArrayNode columnsArray = tableConfigJson.putArray("columns"); diff --git a/openmetadata-spec/src/main/resources/json/schema/type/customProperties/complexTypes.json b/openmetadata-spec/src/main/resources/json/schema/type/customProperties/complexTypes.json index 307eb953dbe..ff9034ac95c 100644 --- a/openmetadata-spec/src/main/resources/json/schema/type/customProperties/complexTypes.json +++ b/openmetadata-spec/src/main/resources/json/schema/type/customProperties/complexTypes.json @@ -127,9 +127,7 @@ "type": "string", "description": "The cell value of each column in the row." } - }, - "minItems": 1, - "maxItems": 10 + } } }, "required": ["columns"], diff --git a/openmetadata-spec/src/main/resources/json/schema/type/customProperties/tableConfig.json b/openmetadata-spec/src/main/resources/json/schema/type/customProperties/tableConfig.json index ca8fb6feece..d45cb45a9f9 100644 --- a/openmetadata-spec/src/main/resources/json/schema/type/customProperties/tableConfig.json +++ b/openmetadata-spec/src/main/resources/json/schema/type/customProperties/tableConfig.json @@ -17,13 +17,6 @@ "maxItems": 3, "uniqueItems": true }, - "rowCount": { - "type": "integer", - "default": 10, - "description": "Number of rows. Defaults to maxRows if not explicitly set.", - "minimum": 1, - "maximum": 10 - }, "minColumns": { "type": "integer", "default": 1, @@ -33,16 +26,6 @@ "type": "integer", "default": 3, "$comment": "For internal use only: Maximum number of columns." - }, - "minRows": { - "type": "integer", - "default": 1, - "$comment": "For internal use only: Minimum number of rows." - }, - "maxRows": { - "type": "integer", - "default": 10, - "$comment": "For internal use only: Maximum number of rows." } }, "required": ["columns"], diff --git a/openmetadata-ui/src/main/resources/ui/playwright/constant/customProperty.ts b/openmetadata-ui/src/main/resources/ui/playwright/constant/customProperty.ts index ccfbfa985c8..a0bc78e8409 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/constant/customProperty.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/constant/customProperty.ts @@ -48,25 +48,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'containers', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_dashboard: { @@ -79,25 +69,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'dashboards', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_database: { @@ -110,25 +90,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'databases', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_databaseSchema: { @@ -141,25 +111,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'databaseSchemas', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_glossaryTerm: { @@ -172,25 +132,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'glossaryTerm', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_mlmodel: { @@ -203,25 +153,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'mlmodels', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_pipeline: { @@ -234,25 +174,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: true, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'pipelines', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_searchIndex: { @@ -265,25 +195,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'searchIndexes', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_storedProcedure: { @@ -296,25 +216,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'storedProcedures', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_table: { @@ -327,25 +237,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'tables', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_topic: { @@ -358,25 +258,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'topics', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_apiCollection: { name: 'apiCollection', @@ -388,25 +278,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'apiCollections', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_apiEndpoint: { @@ -419,25 +299,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'apiEndpoints', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_dataProduct: { name: 'dataProduct', @@ -449,25 +319,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'dataProducts', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_dashboardDataModel: { name: 'dataModel', @@ -479,25 +339,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'dashboardDataModels', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, entity_metric: { name: 'metric', @@ -509,25 +359,15 @@ export const CUSTOM_PROPERTIES_ENTITIES = { values: ['enum1', 'enum2', 'enum3'], multiSelect: false, }, - enumWithDescriptionConfig: { - values: [ - { - key: 'enumWithDescription1', - description: 'This is enumWithDescription1', - }, - { - key: 'enumWithDescription2', - description: 'This is enumWithDescription2', - }, - ], - multiSelect: false, - }, dateFormatConfig: 'yyyy-MM-dd', dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss', timeFormatConfig: 'HH:mm:ss', entityReferenceConfig: ['User', 'Team'], entityObj: {}, entityApiType: 'metrics', + tableConfig: { + columns: ['pw-column1', 'pw-column2'], + }, }, }; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Customproperties-part2.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Customproperties-part2.spec.ts index 7e2d4022bdc..c2df89ac1aa 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Customproperties-part2.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Customproperties-part2.spec.ts @@ -52,6 +52,30 @@ test.describe('Custom properties with custom property config', () => { }); }); + test.describe('Add update and delete Table custom properties', () => { + Object.values(CUSTOM_PROPERTIES_ENTITIES).forEach(async (entity) => { + const propertyName = `pwcustomproperty${entity.name}test${uuid()}`; + + test(`Add Table custom property for ${entity.name}`, async ({ page }) => { + test.slow(true); + + await settingClick(page, entity.entityApiType, true); + + await addCustomPropertiesForEntity({ + page, + propertyName, + customPropertyData: entity, + customType: 'Table', + tableConfig: entity.tableConfig, + }); + + await editCreatedProperty(page, propertyName, 'Table'); + + await deleteCreatedProperty(page, propertyName); + }); + }); + }); + test.describe( 'Add update and delete Entity Reference custom properties', () => { diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/customProperty.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/customProperty.ts index bd9de3b2f39..1133df89195 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/customProperty.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/customProperty.ts @@ -29,6 +29,7 @@ export enum CustomPropertyType { MARKDOWN = 'Markdown', } export enum CustomPropertyTypeByName { + TABLE_CP = 'table-cp', STRING = 'string', INTEGER = 'integer', MARKDOWN = 'markdown', @@ -56,6 +57,27 @@ export interface CustomProperty { }; } +export const fillTextInputDetails = async ( + page: Page, + text: string, + columnName: string +) => { + await page + .locator(`div[data-state-props-id="${columnName}"]`) + .last() + .dblclick(); + + await page + .getByTestId('edit-table-type-property-modal') + .getByRole('textbox') + .fill(text); + + await page + .locator(`div[data-state-props-id="${columnName}"]`) + .last() + .press('Enter', { delay: 100 }); +}; + export const setValueForProperty = async (data: { page: Page; propertyName: string; @@ -203,6 +225,19 @@ export const setValueForProperty = async (data: { break; } + + case 'table-cp': { + const values = value.split(','); + await page.locator('[data-testid="add-new-row"]').click(); + + await fillTextInputDetails(page, values[0], 'pw-column1'); + + await fillTextInputDetails(page, values[1], 'pw-column2'); + + await page.locator('[data-testid="update-table-type-property"]').click(); + + break; + } } await patchRequest; }; @@ -224,7 +259,7 @@ export const validateValueForProperty = async (data: { .locator(`[data-testid="toggle-${propertyName}"]`) .isVisible(); - if (toggleBtnVisibility) { + if (toggleBtnVisibility && propertyType !== 'table-cp') { await container.locator(`[data-testid="toggle-${propertyName}"]`).click(); } @@ -241,6 +276,12 @@ export const validateValueForProperty = async (data: { ); } else if (propertyType === 'sqlQuery') { await expect(container.locator('.CodeMirror-scroll')).toContainText(value); + } else if (propertyType === 'table-cp') { + const values = value.split(','); + + await expect( + page.getByRole('row', { name: `${values[0]} ${values[1]}` }) + ).toBeVisible(); } else if ( ![ 'entityReference', @@ -341,6 +382,12 @@ export const getPropertyValues = ( newValue: '2025-07-09 15:07:59', }; + case 'table-cp': + return { + value: 'column1,column2', + newValue: 'column3,column4', + }; + default: return { value: '', @@ -451,6 +498,15 @@ export const createCustomPropertyForEntity = async ( }, } : {}), + ...(item.name === 'table-cp' + ? { + customPropertyConfig: { + config: { + columns: ['pw-column1', 'pw-column2'], + }, + }, + } + : {}), }, } ); @@ -488,19 +544,16 @@ export const addCustomPropertiesForEntity = async ({ enumConfig, formatConfig, entityReferenceConfig, - enumWithDescriptionConfig, + tableConfig, }: { page: Page; propertyName: string; customPropertyData: { description: string }; customType: string; enumConfig?: { values: string[]; multiSelect: boolean }; - enumWithDescriptionConfig?: { - values: { key: string; description: string }[]; - multiSelect: boolean; - }; formatConfig?: string; entityReferenceConfig?: string[]; + tableConfig?: { columns: string[] }; }) => { // Add Custom property for selected entity await page.click('[data-testid="add-field-button"]'); @@ -578,26 +631,14 @@ export const addCustomPropertiesForEntity = async ({ await page.click('#root\\/multiSelect'); } } - // Enum With Description configuration - if (customType === 'Enum With Descriptions' && enumWithDescriptionConfig) { - for await (const [ - index, - val, - ] of enumWithDescriptionConfig.values.entries()) { - await page.locator('[data-testid="add-enum-description-config"]').click(); - await page.locator(`#key-${index}`).fill(val.key); - await page.locator(descriptionBox).nth(index).fill(val.description); + // Table configuration + if (customType === 'Table' && tableConfig) { + for (const val of tableConfig.columns) { + await page.click('#root\\/columns'); + await page.fill('#root\\/columns', val); + await page.press('#root\\/columns', 'Enter'); } await clickOutside(page); - - if (enumWithDescriptionConfig.multiSelect) { - await page.click('#root\\/multiSelect'); - } - - await page - .locator(descriptionBox) - .nth(2) - .fill(customPropertyData.description); } // Entity reference configuration @@ -626,9 +667,8 @@ export const addCustomPropertiesForEntity = async ({ } // Description - if (customType !== 'Enum With Descriptions') { - await page.fill(descriptionBox, customPropertyData.description); - } + + await page.fill(descriptionBox, customPropertyData.description); const createPropertyPromise = page.waitForResponse( '/api/v1/metadata/types/name/*?fields=customProperties' @@ -663,22 +703,14 @@ export const editCreatedProperty = async ( ).toContainText('["enum1","enum2","enum3"]'); } - if (type === 'Enum With Descriptions') { - await expect( - page - .getByRole('row', { - name: `${propertyName} enumWithDescriptions enumWithDescription1`, - }) - .getByTestId('enum-with-description-config') - ).toBeVisible(); + if (type === 'Table') { + await expect(page.getByText('Columns:pw-column1pw-column2')).toBeVisible(); } await editButton.click(); - if (type !== 'Enum With Descriptions') { - await page.locator(descriptionBox).fill(''); - await page.locator(descriptionBox).fill('This is new description'); - } + await page.locator(descriptionBox).fill(''); + await page.locator(descriptionBox).fill('This is new description'); if (type === 'Enum') { await page.click('#root\\/customPropertyConfig'); @@ -686,10 +718,6 @@ export const editCreatedProperty = async ( await page.press('#root\\/customPropertyConfig', 'Enter'); await clickOutside(page); } - if (type === 'Enum With Descriptions') { - await page.locator(descriptionBox).nth(0).fill(''); - await page.locator(descriptionBox).nth(0).fill('This is new description'); - } if (ENTITY_REFERENCE_PROPERTIES.includes(type ?? '')) { await page.click('#root\\/customPropertyConfig'); @@ -723,16 +751,6 @@ export const editCreatedProperty = async ( ).toContainText('["enum1","enum2","enum3","updatedValue"]'); } - if (type === 'Enum With Descriptions') { - await expect( - page - .getByRole('row', { - name: `${propertyName} enumWithDescriptions enumWithDescription1`, - }) - .getByTestId('enum-with-description-config') - ).toBeVisible(); - } - if (ENTITY_REFERENCE_PROPERTIES.includes(type ?? '')) { await expect( page.locator( diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/date-time.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/date-time.svg new file mode 100644 index 00000000000..ecd706f3411 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/date-time.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/date.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/date.svg new file mode 100644 index 00000000000..25451c0406f --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/date.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/duration.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/duration.svg new file mode 100644 index 00000000000..9cee0d77a68 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/duration.svg @@ -0,0 +1,3 @@ + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/email.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/email.svg new file mode 100644 index 00000000000..bc15adf6207 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/email.svg @@ -0,0 +1,4 @@ + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/entity-list.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/entity-list.svg new file mode 100644 index 00000000000..9457f32561b --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/entity-list.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/entity.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/entity.svg new file mode 100644 index 00000000000..1cb51fca34d --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/entity.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/enum.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/enum.svg new file mode 100644 index 00000000000..3744491c26a --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/enum.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/integer.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/integer.svg new file mode 100644 index 00000000000..2e73065c979 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/integer.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/markdown.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/markdown.svg new file mode 100644 index 00000000000..0786a39254e --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/markdown.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/number.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/number.svg new file mode 100644 index 00000000000..715ebe96b0c --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/number.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/sql-query.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/sql-query.svg new file mode 100644 index 00000000000..54a3072f160 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/sql-query.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/string.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/string.svg new file mode 100644 index 00000000000..f6b7526b5e8 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/string.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/table.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/table.svg new file mode 100644 index 00000000000..caaff5cfbc5 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/table.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/time-interval.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/time-interval.svg new file mode 100644 index 00000000000..70424ee73e1 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/time-interval.svg @@ -0,0 +1,3 @@ + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/time.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/time.svg new file mode 100644 index 00000000000..a7517f3aac9 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/time.svg @@ -0,0 +1,4 @@ + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/timestamp.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/timestamp.svg new file mode 100644 index 00000000000..7e72e98bd40 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/customproperties/timestamp.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Modals/ModalWithCustomProperty/ModalWithMarkdownEditor.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Modals/ModalWithCustomProperty/ModalWithMarkdownEditor.interface.ts index 5fa33f3b60b..6696df30356 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Modals/ModalWithCustomProperty/ModalWithMarkdownEditor.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/Modals/ModalWithCustomProperty/ModalWithMarkdownEditor.interface.ts @@ -11,14 +11,13 @@ * limitations under the License. */ import { EntityType } from '../../../enums/entity.enum'; -import { EntityReference, ValueClass } from '../../../generated/entity/type'; +import { EntityReference } from '../../../generated/entity/type'; export type ExtensionDataTypes = | string | string[] | EntityReference | EntityReference[] - | ValueClass[] | { start: string; end: string }; export interface ExtensionDataProps { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/AddCustomProperty/AddCustomProperty.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/AddCustomProperty/AddCustomProperty.tsx index f89b341fcd8..11a0cb93dfa 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/AddCustomProperty/AddCustomProperty.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/AddCustomProperty/AddCustomProperty.tsx @@ -24,6 +24,7 @@ import React, { } from 'react'; import { useHistory, useParams } from 'react-router-dom'; import { + CUSTOM_PROPERTIES_ICON_MAP, ENTITY_REFERENCE_OPTIONS, PROPERTY_TYPES_WITH_ENTITY_REFERENCE, PROPERTY_TYPES_WITH_FORMAT, @@ -50,6 +51,7 @@ import { getTypeByFQN, getTypeListByCategory, } from '../../../../rest/metadataTypeAPI'; +import { getEntityName } from '../../../../utils/EntityUtils'; import { generateFormFields } from '../../../../utils/formUtils'; import { getSettingOptionByEntityType } from '../../../../utils/GlobalSettingsUtils'; import { getSettingPath } from '../../../../utils/RouterUtils'; @@ -95,12 +97,27 @@ const AddCustomProperty = () => { ); const propertyTypeOptions = useMemo(() => { - return map(propertyTypes, (type) => ({ - key: type.name, + return map(propertyTypes, (type) => { + const Icon = + CUSTOM_PROPERTIES_ICON_MAP[ + type.name as keyof typeof CUSTOM_PROPERTIES_ICON_MAP + ]; + // Remove -cp from the name and convert to start case - label: startCase((type.displayName ?? type.name).replace(/-cp/g, '')), - value: type.id, - })); + const title = startCase(getEntityName(type).replace(/-cp/g, '')); + + return { + searchField: title, + key: type.name, + label: ( +
+ {Icon && } + {title} +
+ ), + value: type.id, + }; + }); }, [propertyTypes]); const { @@ -171,7 +188,6 @@ const AddCustomProperty = () => { formatConfig: string; entityReferenceConfig: string[]; multiSelect?: boolean; - rowCount: number; columns: string[]; } ) => { @@ -208,7 +224,6 @@ const AddCustomProperty = () => { customPropertyConfig = { config: { columns: data.columns, - rowCount: data.rowCount ?? 10, }, }; } @@ -220,7 +235,6 @@ const AddCustomProperty = () => { 'formatConfig', 'entityReferenceConfig', 'enumConfig', - 'rowCount', 'columns', ]), propertyType: { @@ -281,8 +295,8 @@ const AddCustomProperty = () => { field: t('label.type'), })}`, showSearch: true, - filterOption: (input: string, option: { label: string }) => { - return (option?.label ?? '') + filterOption: (input: string, option: { searchField: string }) => { + return (option?.searchField ?? '') .toLowerCase() .includes(input.toLowerCase()); }, @@ -423,31 +437,6 @@ const AddCustomProperty = () => { }, ], }, - { - name: 'rowCount', - label: t('label.row-count'), - type: FieldTypes.NUMBER, - required: false, - id: 'root/rowCount', - props: { - 'data-testid': 'rowCount', - size: 'default', - style: { width: '100%' }, - placeholder: t('label.row-count'), - }, - rules: [ - { - min: 1, - type: 'number', - max: 10, - message: t('message.entity-size-in-between', { - entity: t('label.row-count'), - min: 1, - max: 10, - }), - }, - ], - }, ]; const firstPanelChildren = ( @@ -457,9 +446,6 @@ const AddCustomProperty = () => { className="m-t-md" data-testid="custom-property-form" form={form} - initialValues={{ - rowCount: 10, - }} layout="vertical" onFinish={handleSubmit} onFocus={handleFieldFocus}> diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/CustomPropertyTable.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/CustomPropertyTable.tsx index 2d1f136ffe5..81762261bcc 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/CustomPropertyTable.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/CustomPropertyTable.tsx @@ -12,11 +12,12 @@ */ import { Button, Space, Tooltip, Typography } from 'antd'; import { ColumnsType } from 'antd/lib/table'; -import { isArray, isEmpty, isString, isUndefined } from 'lodash'; +import { isArray, isEmpty, isString, isUndefined, startCase } from 'lodash'; import React, { FC, Fragment, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactComponent as IconEdit } from '../../../assets/svg/edit-new.svg'; import { ReactComponent as IconDelete } from '../../../assets/svg/ic-delete.svg'; +import { CUSTOM_PROPERTIES_ICON_MAP } from '../../../constants/CustomProperty.constants'; import { ADD_CUSTOM_PROPERTIES_DOCS } from '../../../constants/docs.constants'; import { NO_PERMISSION_FOR_ACTION } from '../../../constants/HelperTextUtil'; import { TABLE_SCROLL_VALUE } from '../../../constants/Table.constants'; @@ -27,6 +28,7 @@ import ErrorPlaceHolder from '../../common/ErrorWithPlaceholder/ErrorPlaceHolder import RichTextEditorPreviewer from '../../common/RichTextEditor/RichTextEditorPreviewer'; import Table from '../../common/Table/Table'; import ConfirmationModal from '../../Modals/ConfirmationModal/ConfirmationModal'; +import './custom-property-table.less'; import { CustomPropertyTableProp } from './CustomPropertyTable.interface'; import EditCustomPropertyModal, { FormData, @@ -116,7 +118,21 @@ export const CustomPropertyTable: FC = ({ title: t('label.type'), dataIndex: 'propertyType', key: 'propertyType', - render: (propertyType) => getEntityName(propertyType), + render: (propertyType: CustomProperty['propertyType']) => { + const Icon = + CUSTOM_PROPERTIES_ICON_MAP[ + propertyType.name as keyof typeof CUSTOM_PROPERTIES_ICON_MAP + ]; + + return ( +
+ {Icon && } + + {startCase(getEntityName(propertyType).replace(/-cp/g, ''))} + +
+ ); + }, }, { title: t('label.config'), @@ -153,12 +169,6 @@ export const CustomPropertyTable: FC = ({ ))} - - {`${t( - 'label.row-count' - )}: `} - {config?.rowCount ?? 10} - ); } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/custom-property-table.less b/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/custom-property-table.less new file mode 100644 index 00000000000..5ce97d8bee8 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/custom-property-table.less @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import (reference) url('../../../styles/variables.less'); + +.custom-property-type-chip { + background: @grey-1; + border: 1px solid @text-color; + padding: 4px 8px; + border-radius: 15px; + width: fit-content; +} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/CustomPropertyTable.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/CustomPropertyTable.tsx index 3b59cca038f..7fd56cb3500 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/CustomPropertyTable.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/CustomPropertyTable.tsx @@ -294,7 +294,10 @@ export const CustomPropertyTable = ({ ) : ( - + {dataSourceColumns.map((columns, colIndex) => ( {columns.map((record) => ( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/PropertyValue.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/PropertyValue.tsx index d000e3bb89f..af4d82a1a38 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/PropertyValue.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/PropertyValue.tsx @@ -710,7 +710,6 @@ export const PropertyValue: FC = ({ columns={columns} isUpdating={isLoading} isVisible={showInput} - maxRowCount={config?.rowCount ?? 10} property={property} rows={value?.rows ?? []} onCancel={onHideInput} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/TableTypeProperty/EditTableTypePropertyModal.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/TableTypeProperty/EditTableTypePropertyModal.tsx index b13a31bb2c4..a453c7ef389 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/TableTypeProperty/EditTableTypePropertyModal.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/CustomPropertyTable/TableTypeProperty/EditTableTypePropertyModal.tsx @@ -13,7 +13,7 @@ import ReactDataGrid from '@inovua/reactdatagrid-community'; import '@inovua/reactdatagrid-community/index.css'; import { TypeComputedProps } from '@inovua/reactdatagrid-community/types'; -import { Button, Modal, Tooltip, Typography } from 'antd'; +import { Button, Modal, Typography } from 'antd'; import { isEmpty, omit } from 'lodash'; import React, { FC, MutableRefObject, useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -28,7 +28,6 @@ interface EditTableTypePropertyModalProps { property: CustomProperty; columns: string[]; rows: Record[]; - maxRowCount: number; onCancel: () => void; onSave: (data: TableTypePropertyValueType) => Promise; } @@ -41,7 +40,6 @@ const EditTableTypePropertyModal: FC = ({ property, columns, rows, - maxRowCount, onCancel, onSave, }) => { @@ -168,28 +166,23 @@ const EditTableTypePropertyModal: FC = ({ data-testid="edit-table-type-property-modal" footer={
- - - +
-