diff --git a/ingestion/setup.py b/ingestion/setup.py index aa5bd5aa27c..ff46558826a 100644 --- a/ingestion/setup.py +++ b/ingestion/setup.py @@ -45,7 +45,7 @@ VERSIONS = { "sqlalchemy-databricks": "sqlalchemy-databricks~=0.1", "databricks-sdk": "databricks-sdk>=0.18.0,<0.20.0", "trino": "trino[sqlalchemy]", - "spacy": "spacy~=3.7", + "spacy": "spacy<3.8", "looker-sdk": "looker-sdk>=22.20.0", "lkml": "lkml~=1.3", "tableau": "tableau-api-lib~=0.1", diff --git a/ingestion/src/metadata/examples/workflows/salesforce.yaml b/ingestion/src/metadata/examples/workflows/salesforce.yaml index 6822679d797..290e208d22f 100644 --- a/ingestion/src/metadata/examples/workflows/salesforce.yaml +++ b/ingestion/src/metadata/examples/workflows/salesforce.yaml @@ -7,6 +7,7 @@ source: username: username password: password securityToken: securityToken + organizationId: organizationId sobjectName: sobjectName # sslConfig: # caCertificate: | diff --git a/ingestion/src/metadata/ingestion/source/database/salesforce/connection.py b/ingestion/src/metadata/ingestion/source/database/salesforce/connection.py index 9ead18111c4..9cfd79e0884 100644 --- a/ingestion/src/metadata/ingestion/source/database/salesforce/connection.py +++ b/ingestion/src/metadata/ingestion/source/database/salesforce/connection.py @@ -15,7 +15,6 @@ Source connection handler from typing import Optional from simple_salesforce.api import Salesforce -from sqlalchemy.engine import Engine from metadata.generated.schema.entity.automations.workflow import ( Workflow as AutomationWorkflow, @@ -27,14 +26,17 @@ from metadata.ingestion.connections.test_connections import test_connection_step from metadata.ingestion.ometa.ometa_api import OpenMetadata -def get_connection(connection: SalesforceConnection) -> Engine: +def get_connection(connection: SalesforceConnection) -> Salesforce: """ Create connection """ return Salesforce( username=connection.username, password=connection.password.get_secret_value(), - security_token=connection.securityToken.get_secret_value(), + security_token=connection.securityToken.get_secret_value() + if connection.securityToken + else "", + organizationId=connection.organizationId if connection.organizationId else "", domain=connection.salesforceDomain, version=connection.salesforceApiVersion, **connection.connectionArguments.root if connection.connectionArguments else {}, diff --git a/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/index.md b/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/index.md index cf92b0c9c6d..1a607cb7059 100644 --- a/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/index.md +++ b/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/index.md @@ -49,6 +49,13 @@ These are the permissions you will require to fetch the metadata from Salesforce - **Username**: Username to connect to the Salesforce. This user should have the access as defined in requirements. - **Password**: Password to connect to Salesforce. - **Security Token**: Salesforce Security Token is required to access the metadata through APIs. You can checkout [this doc](https://help.salesforce.com/s/articleView?id=sf.user_security_token.htm&type=5) on how to get the security token. +- **Organization ID**: Salesforce Organization ID is the unique identifier for your Salesforce identity. You can check out [this doc](https://help.salesforce.com/s/articleView?id=000385215&type=1) on how to get the your Salesforce Organization ID. + {% note %} + **Note**: You need to provide `15` digit organization id in this section. for e.g. `00DIB000004nDEq`, which you can find by following the steps mentioned in above doc (`Salesforce dashboard->Setup->Company Profile->Company Information->Salesforce.com Organization Id`). + {% /note %} + {% note %} + **Note**: If you want to access salesforce metadata without token(only by using organization id), you will need to setup your ip in trusted ip ranges. You can go (`Salesforce dashboard->Setup->Security->Network Access->Trusted IP Ranges`) to configure this. You can check [here](https://help.salesforce.com/s/articleView?id=sf.security_networkaccess.htm&type=5) to configure your ip in trusted ip ranges. + {% /note %} - **Salesforce Object Name**: Specify the Salesforce Object Name in case you want to ingest a specific object. If left blank, we will ingest all the Objects. - **Salesforce API Version**: Follow the steps mentioned [here](https://help.salesforce.com/s/articleView?id=000386929&type=1) to get the API version. Enter the numerical value in the field, For example `42.0`. - **Salesforce Domain**: When connecting to Salesforce, you can specify the domain to use for accessing the platform. The common domains include `login` and `test`, and you can also utilize Salesforce My Domain. diff --git a/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/yaml.md b/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/yaml.md index c2d92e08a27..c4573a311ad 100644 --- a/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/yaml.md +++ b/openmetadata-docs/content/v1.5.x/connectors/database/salesforce/yaml.md @@ -83,18 +83,30 @@ This is a sample config for Salesforce: {% codeInfo srNumber=5 %} -**sobjectName**: Specify the Salesforce Object Name in case you want to ingest a specific object. If left blank, we will ingest all the Objects. +**Organization ID**: Salesforce Organization ID is the unique identifier for your Salesforce identity. You can check out [this doc](https://help.salesforce.com/s/articleView?id=000385215&type=1) on how to get the your Salesforce Organization ID. +{% note %} +**Note**: You need to provide `15` digit organization id in this section. for e.g. `00DIB000004nDEq`, which you can find by following the steps mentioned in above doc (`Salesforce dashboard->Setup->Company Profile->Company Information->Salesforce.com Organization Id`). +{% /note %} +{% note %} +**Note**: If you want to access salesforce metadata without token(only by using organization id), you will need to setup your ip in trusted ip ranges. You can go (`Salesforce dashboard->Setup->Security->Network Access->Trusted IP Ranges`) to configure this. You can check [here](https://help.salesforce.com/s/articleView?id=sf.security_networkaccess.htm&type=5) to configure your ip in trusted ip ranges. +{% /note %} {% /codeInfo %} {% codeInfo srNumber=6 %} -**salesforceApiVersion**: Follow the steps mentioned [here](https://help.salesforce.com/s/articleView?id=000386929&type=1) to get the API version. Enter the numerical value in the field, For example `42.0`. +**sobjectName**: Specify the Salesforce Object Name in case you want to ingest a specific object. If left blank, we will ingest all the Objects. {% /codeInfo %} {% codeInfo srNumber=7 %} +**salesforceApiVersion**: Follow the steps mentioned [here](https://help.salesforce.com/s/articleView?id=000386929&type=1) to get the API version. Enter the numerical value in the field, For example `42.0`. + +{% /codeInfo %} + +{% codeInfo srNumber=8 %} + **salesforceDomain**: When connecting to Salesforce, you can specify the domain to use for accessing the platform. The common domains include `login` and `test`, and you can also utilize Salesforce My Domain. By default, the domain `login` is used for accessing Salesforce. @@ -108,13 +120,13 @@ By default, the domain `login` is used for accessing Salesforce. #### Advanced Configuration -{% codeInfo srNumber=8 %} +{% codeInfo srNumber=9 %} **Connection Options (Optional)**: Enter the details for any additional connection options that can be sent to database during the connection. These details must be added as Key-Value pairs. {% /codeInfo %} -{% codeInfo srNumber=9 %} +{% codeInfo srNumber=10 %} **Connection Arguments (Optional)**: Enter the details for any additional connection arguments such as security or protocol configs that can be sent to database during the connection. These details must be added as Key-Value pairs. @@ -144,19 +156,22 @@ source: securityToken: securityToken ``` ```yaml {% srNumber=5 %} - sobjectName: sobjectName + organizationId: organizationId ``` ```yaml {% srNumber=6 %} - salesforceApiVersion: 42.0 + sobjectName: sobjectName ``` ```yaml {% srNumber=7 %} - salesforceDomain: login + salesforceApiVersion: 42.0 ``` ```yaml {% srNumber=8 %} + salesforceDomain: login +``` +```yaml {% srNumber=9 %} # connectionOptions: # key: value ``` -```yaml {% srNumber=9 %} +```yaml {% srNumber=10 %} # connectionArguments: # key: value ``` diff --git a/openmetadata-docs/content/v1.5.x/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md b/openmetadata-docs/content/v1.5.x/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md index 804ee1574e1..af567c1efc6 100644 --- a/openmetadata-docs/content/v1.5.x/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md +++ b/openmetadata-docs/content/v1.5.x/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md @@ -13,6 +13,7 @@ slug: /main-concepts/metadata-standard/schemas/entity/services/connections/datab - **`username`** *(string)*: Username to connect to the Salesforce. This user should have privileges to read all the metadata in Redshift. - **`password`** *(string)*: Password to connect to the Salesforce. - **`securityToken`** *(string)*: Salesforce Security Token. +- **`organizationId`** *(string)*: Salesforce Organization ID. - **`sobjectName`** *(string)*: Salesforce Object Name. - **`databaseName`** *(string)*: Optional name to give to the database in OpenMetadata. If left blank, we will use default as the database name. - **`salesforceApiVersion`** *(string)*: API version of the Salesforce instance. Default: `42.0`. diff --git a/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/index.md b/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/index.md index cf92b0c9c6d..1a607cb7059 100644 --- a/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/index.md +++ b/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/index.md @@ -49,6 +49,13 @@ These are the permissions you will require to fetch the metadata from Salesforce - **Username**: Username to connect to the Salesforce. This user should have the access as defined in requirements. - **Password**: Password to connect to Salesforce. - **Security Token**: Salesforce Security Token is required to access the metadata through APIs. You can checkout [this doc](https://help.salesforce.com/s/articleView?id=sf.user_security_token.htm&type=5) on how to get the security token. +- **Organization ID**: Salesforce Organization ID is the unique identifier for your Salesforce identity. You can check out [this doc](https://help.salesforce.com/s/articleView?id=000385215&type=1) on how to get the your Salesforce Organization ID. + {% note %} + **Note**: You need to provide `15` digit organization id in this section. for e.g. `00DIB000004nDEq`, which you can find by following the steps mentioned in above doc (`Salesforce dashboard->Setup->Company Profile->Company Information->Salesforce.com Organization Id`). + {% /note %} + {% note %} + **Note**: If you want to access salesforce metadata without token(only by using organization id), you will need to setup your ip in trusted ip ranges. You can go (`Salesforce dashboard->Setup->Security->Network Access->Trusted IP Ranges`) to configure this. You can check [here](https://help.salesforce.com/s/articleView?id=sf.security_networkaccess.htm&type=5) to configure your ip in trusted ip ranges. + {% /note %} - **Salesforce Object Name**: Specify the Salesforce Object Name in case you want to ingest a specific object. If left blank, we will ingest all the Objects. - **Salesforce API Version**: Follow the steps mentioned [here](https://help.salesforce.com/s/articleView?id=000386929&type=1) to get the API version. Enter the numerical value in the field, For example `42.0`. - **Salesforce Domain**: When connecting to Salesforce, you can specify the domain to use for accessing the platform. The common domains include `login` and `test`, and you can also utilize Salesforce My Domain. diff --git a/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/yaml.md b/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/yaml.md index c2d92e08a27..a1d28389c73 100644 --- a/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/yaml.md +++ b/openmetadata-docs/content/v1.6.x-SNAPSHOT/connectors/database/salesforce/yaml.md @@ -83,17 +83,28 @@ This is a sample config for Salesforce: {% codeInfo srNumber=5 %} +**Organization ID**: Salesforce Organization ID is the unique identifier for your Salesforce identity. You can check out [this doc](https://help.salesforce.com/s/articleView?id=000385215&type=1) on how to get the your Salesforce Organization ID. +{% note %} +**Note**: You need to provide `15` digit organization id in this section. for e.g. `00DIB000004nDEq`, which you can find by following the steps mentioned in above doc (`Salesforce dashboard->Setup->Company Profile->Company Information->Salesforce.com Organization Id`). +{% /note %} +{% note %} +**Note**: If you want to access salesforce metadata without token(only by using organization id), you will need to setup your ip in trusted ip ranges. You can go (`Salesforce dashboard->Setup->Security->Network Access->Trusted IP Ranges`) to configure this. You can check [here](https://help.salesforce.com/s/articleView?id=sf.security_networkaccess.htm&type=5) to configure your ip in trusted ip ranges. +{% /note %} +{% /codeInfo %} + +{% codeInfo srNumber=6 %} + **sobjectName**: Specify the Salesforce Object Name in case you want to ingest a specific object. If left blank, we will ingest all the Objects. {% /codeInfo %} -{% codeInfo srNumber=6 %} +{% codeInfo srNumber=7 %} **salesforceApiVersion**: Follow the steps mentioned [here](https://help.salesforce.com/s/articleView?id=000386929&type=1) to get the API version. Enter the numerical value in the field, For example `42.0`. {% /codeInfo %} -{% codeInfo srNumber=7 %} +{% codeInfo srNumber=8 %} **salesforceDomain**: When connecting to Salesforce, you can specify the domain to use for accessing the platform. The common domains include `login` and `test`, and you can also utilize Salesforce My Domain. By default, the domain `login` is used for accessing Salesforce. @@ -108,13 +119,13 @@ By default, the domain `login` is used for accessing Salesforce. #### Advanced Configuration -{% codeInfo srNumber=8 %} +{% codeInfo srNumber=9 %} **Connection Options (Optional)**: Enter the details for any additional connection options that can be sent to database during the connection. These details must be added as Key-Value pairs. {% /codeInfo %} -{% codeInfo srNumber=9 %} +{% codeInfo srNumber=10 %} **Connection Arguments (Optional)**: Enter the details for any additional connection arguments such as security or protocol configs that can be sent to database during the connection. These details must be added as Key-Value pairs. @@ -144,19 +155,22 @@ source: securityToken: securityToken ``` ```yaml {% srNumber=5 %} - sobjectName: sobjectName + organizationId: organizationId ``` ```yaml {% srNumber=6 %} - salesforceApiVersion: 42.0 + sobjectName: sobjectName ``` ```yaml {% srNumber=7 %} - salesforceDomain: login + salesforceApiVersion: 42.0 ``` ```yaml {% srNumber=8 %} + salesforceDomain: login +``` +```yaml {% srNumber=9 %} # connectionOptions: # key: value ``` -```yaml {% srNumber=9 %} +```yaml {% srNumber=10 %} # connectionArguments: # key: value ``` diff --git a/openmetadata-docs/content/v1.6.x-SNAPSHOT/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md b/openmetadata-docs/content/v1.6.x-SNAPSHOT/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md index 804ee1574e1..af567c1efc6 100644 --- a/openmetadata-docs/content/v1.6.x-SNAPSHOT/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md +++ b/openmetadata-docs/content/v1.6.x-SNAPSHOT/main-concepts/metadata-standard/schemas/entity/services/connections/database/salesforceConnection.md @@ -13,6 +13,7 @@ slug: /main-concepts/metadata-standard/schemas/entity/services/connections/datab - **`username`** *(string)*: Username to connect to the Salesforce. This user should have privileges to read all the metadata in Redshift. - **`password`** *(string)*: Password to connect to the Salesforce. - **`securityToken`** *(string)*: Salesforce Security Token. +- **`organizationId`** *(string)*: Salesforce Organization ID. - **`sobjectName`** *(string)*: Salesforce Object Name. - **`databaseName`** *(string)*: Optional name to give to the database in OpenMetadata. If left blank, we will use default as the database name. - **`salesforceApiVersion`** *(string)*: API version of the Salesforce instance. Default: `42.0`. diff --git a/openmetadata-spec/src/main/resources/json/schema/entity/services/connections/database/salesforceConnection.json b/openmetadata-spec/src/main/resources/json/schema/entity/services/connections/database/salesforceConnection.json index 10ccc6c7af9..a6d119e899f 100644 --- a/openmetadata-spec/src/main/resources/json/schema/entity/services/connections/database/salesforceConnection.json +++ b/openmetadata-spec/src/main/resources/json/schema/entity/services/connections/database/salesforceConnection.json @@ -37,6 +37,11 @@ "type": "string", "format": "password" }, + "organizationId": { + "title": "Salesforce Organization ID", + "description": "Salesforce Organization ID is the unique identifier for your Salesforce identity", + "type": "string" + }, "sobjectName": { "title": "Object Name", "description": "Salesforce Object Name.", diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts index d91b22d6ae4..c17605b8b9f 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts @@ -275,6 +275,8 @@ test.describe('Observability Alert Flow', () => { test(`${sourceDisplayName} alert`, async ({ page }) => { const ALERT_NAME = generateAlertName(); + test.slow(true); + await test.step('Create alert', async () => { await inputBasicAlertInformation({ page, diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Lineage.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Lineage.spec.ts index 3d5ad521a63..1b3577281f0 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Lineage.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Lineage.spec.ts @@ -70,68 +70,66 @@ test.afterAll('Cleanup', async ({ browser }) => { for (const EntityClass of entities) { const defaultEntity = new EntityClass(); - test.fixme( - `Lineage creation from ${defaultEntity.getType()} entity`, - async ({ browser }) => { - test.slow(true); + test(`Lineage creation from ${defaultEntity.getType()} entity`, async ({ + browser, + }) => { + test.slow(true); - const { page } = await createNewPage(browser); - const { currentEntity, entities, cleanup } = - await setupEntitiesForLineage(page, defaultEntity); + const { page } = await createNewPage(browser); + const { currentEntity, entities, cleanup } = await setupEntitiesForLineage( + page, + defaultEntity + ); - await test.step('Should create lineage for the entity', async () => { - await redirectToHomePage(page); - await currentEntity.visitEntityPage(page); - await visitLineageTab(page); - await verifyColumnLayerInactive(page); - await page.click('[data-testid="edit-lineage"]'); - await performZoomOut(page); - for (const entity of entities) { - await connectEdgeBetweenNodes(page, currentEntity, entity); - } + await test.step('Should create lineage for the entity', async () => { + await redirectToHomePage(page); + await currentEntity.visitEntityPage(page); + await visitLineageTab(page); + await verifyColumnLayerInactive(page); + await page.click('[data-testid="edit-lineage"]'); + await performZoomOut(page); + for (const entity of entities) { + await connectEdgeBetweenNodes(page, currentEntity, entity); + } - await redirectToHomePage(page); - await currentEntity.visitEntityPage(page); - await visitLineageTab(page); - await page - .locator('.react-flow__controls-fitview') - .dispatchEvent('click'); + await redirectToHomePage(page); + await currentEntity.visitEntityPage(page); + await visitLineageTab(page); + await page + .locator('.react-flow__controls-fitview') + .dispatchEvent('click'); - for (const entity of entities) { - await verifyNodePresent(page, entity); - } - }); + for (const entity of entities) { + await verifyNodePresent(page, entity); + } + }); - await test.step('Should create pipeline between entities', async () => { - await page.click('[data-testid="edit-lineage"]'); - await performZoomOut(page); + await test.step('Should create pipeline between entities', async () => { + await page.click('[data-testid="edit-lineage"]'); + await performZoomOut(page); - for (const entity of entities) { - await applyPipelineFromModal(page, currentEntity, entity, pipeline); - } - }); + for (const entity of entities) { + await applyPipelineFromModal(page, currentEntity, entity, pipeline); + } + }); - await test.step( - 'Remove lineage between nodes for the entity', - async () => { - await redirectToHomePage(page); - await currentEntity.visitEntityPage(page); - await visitLineageTab(page); - await page.click('[data-testid="edit-lineage"]'); - await performZoomOut(page); + await test.step('Remove lineage between nodes for the entity', async () => { + await redirectToHomePage(page); + await currentEntity.visitEntityPage(page); + await visitLineageTab(page); + await page.click('[data-testid="edit-lineage"]'); + await performZoomOut(page); - for (const entity of entities) { - await deleteEdge(page, currentEntity, entity); - } - } - ); + for (const entity of entities) { + await deleteEdge(page, currentEntity, entity); + } + }); - await cleanup(); - } - ); + await cleanup(); + }); } -test.fixme('Verify column lineage between tables', async ({ browser }) => { +test('Verify column lineage between tables', async ({ browser }) => { const { page } = await createNewPage(browser); const { apiContext, afterAction } = await getApiContext(page); const table1 = new TableClass(); @@ -169,117 +167,112 @@ test.fixme('Verify column lineage between tables', async ({ browser }) => { await afterAction(); }); -test.fixme( - 'Verify column lineage between table and topic', - async ({ browser }) => { - const { page } = await createNewPage(browser); - const { apiContext, afterAction } = await getApiContext(page); - const table = new TableClass(); - const topic = new TopicClass(); - await table.create(apiContext); - await topic.create(apiContext); +test('Verify column lineage between table and topic', async ({ browser }) => { + const { page } = await createNewPage(browser); + const { apiContext, afterAction } = await getApiContext(page); + const table = new TableClass(); + const topic = new TopicClass(); + await table.create(apiContext); + await topic.create(apiContext); - const sourceTableFqn = get(table, 'entityResponseData.fullyQualifiedName'); - const sourceCol = `${sourceTableFqn}.${get( - table, - 'entityResponseData.columns[0].name' - )}`; - const targetCol = get( - topic, - 'entityResponseData.messageSchema.schemaFields[0].children[0].fullyQualifiedName' - ); + const sourceTableFqn = get(table, 'entityResponseData.fullyQualifiedName'); + const sourceCol = `${sourceTableFqn}.${get( + table, + 'entityResponseData.columns[0].name' + )}`; + const targetCol = get( + topic, + 'entityResponseData.messageSchema.schemaFields[0].children[0].fullyQualifiedName' + ); - await addPipelineBetweenNodes(page, table, topic); - await activateColumnLayer(page); + await addPipelineBetweenNodes(page, table, topic); + await activateColumnLayer(page); - // Add column lineage - await addColumnLineage(page, sourceCol, targetCol); - await page.click('[data-testid="edit-lineage"]'); + // Add column lineage + await addColumnLineage(page, sourceCol, targetCol); + await page.click('[data-testid="edit-lineage"]'); - await removeColumnLineage(page, sourceCol, targetCol); - await page.click('[data-testid="edit-lineage"]'); + await removeColumnLineage(page, sourceCol, targetCol); + await page.click('[data-testid="edit-lineage"]'); - await deleteNode(page, topic); - await table.delete(apiContext); - await topic.delete(apiContext); + await deleteNode(page, topic); + await table.delete(apiContext); + await topic.delete(apiContext); - await afterAction(); - } -); + await afterAction(); +}); -test.fixme( - 'Verify column lineage between topic and api endpoint', - async ({ browser }) => { - const { page } = await createNewPage(browser); - const { apiContext, afterAction } = await getApiContext(page); - const topic = new TopicClass(); - const apiEndpoint = new ApiEndpointClass(); +test('Verify column lineage between topic and api endpoint', async ({ + browser, +}) => { + const { page } = await createNewPage(browser); + const { apiContext, afterAction } = await getApiContext(page); + const topic = new TopicClass(); + const apiEndpoint = new ApiEndpointClass(); - await topic.create(apiContext); - await apiEndpoint.create(apiContext); + await topic.create(apiContext); + await apiEndpoint.create(apiContext); - const sourceCol = get( - topic, - 'entityResponseData.messageSchema.schemaFields[0].children[0].fullyQualifiedName' - ); + const sourceCol = get( + topic, + 'entityResponseData.messageSchema.schemaFields[0].children[0].fullyQualifiedName' + ); - const targetCol = get( - apiEndpoint, - 'entityResponseData.responseSchema.schemaFields[0].children[1].fullyQualifiedName' - ); + const targetCol = get( + apiEndpoint, + 'entityResponseData.responseSchema.schemaFields[0].children[1].fullyQualifiedName' + ); - await addPipelineBetweenNodes(page, topic, apiEndpoint); - await activateColumnLayer(page); + await addPipelineBetweenNodes(page, topic, apiEndpoint); + await activateColumnLayer(page); - // Add column lineage - await addColumnLineage(page, sourceCol, targetCol); - await page.click('[data-testid="edit-lineage"]'); + // Add column lineage + await addColumnLineage(page, sourceCol, targetCol); + await page.click('[data-testid="edit-lineage"]'); - await removeColumnLineage(page, sourceCol, targetCol); - await page.click('[data-testid="edit-lineage"]'); + await removeColumnLineage(page, sourceCol, targetCol); + await page.click('[data-testid="edit-lineage"]'); - await deleteNode(page, apiEndpoint); - await topic.delete(apiContext); - await apiEndpoint.delete(apiContext); + await deleteNode(page, apiEndpoint); + await topic.delete(apiContext); + await apiEndpoint.delete(apiContext); - await afterAction(); - } -); + await afterAction(); +}); -test.fixme( - 'Verify column lineage between table and api endpoint', - async ({ browser }) => { - const { page } = await createNewPage(browser); - const { apiContext, afterAction } = await getApiContext(page); - const table = new TableClass(); - const apiEndpoint = new ApiEndpointClass(); - await table.create(apiContext); - await apiEndpoint.create(apiContext); +test('Verify column lineage between table and api endpoint', async ({ + browser, +}) => { + const { page } = await createNewPage(browser); + const { apiContext, afterAction } = await getApiContext(page); + const table = new TableClass(); + const apiEndpoint = new ApiEndpointClass(); + await table.create(apiContext); + await apiEndpoint.create(apiContext); - const sourceTableFqn = get(table, 'entityResponseData.fullyQualifiedName'); - const sourceCol = `${sourceTableFqn}.${get( - table, - 'entityResponseData.columns[0].name' - )}`; - const targetCol = get( - apiEndpoint, - 'entityResponseData.responseSchema.schemaFields[0].children[0].fullyQualifiedName' - ); + const sourceTableFqn = get(table, 'entityResponseData.fullyQualifiedName'); + const sourceCol = `${sourceTableFqn}.${get( + table, + 'entityResponseData.columns[0].name' + )}`; + const targetCol = get( + apiEndpoint, + 'entityResponseData.responseSchema.schemaFields[0].children[0].fullyQualifiedName' + ); - await addPipelineBetweenNodes(page, table, apiEndpoint); - await activateColumnLayer(page); + await addPipelineBetweenNodes(page, table, apiEndpoint); + await activateColumnLayer(page); - // Add column lineage - await addColumnLineage(page, sourceCol, targetCol); - await page.click('[data-testid="edit-lineage"]'); + // Add column lineage + await addColumnLineage(page, sourceCol, targetCol); + await page.click('[data-testid="edit-lineage"]'); - await removeColumnLineage(page, sourceCol, targetCol); - await page.click('[data-testid="edit-lineage"]'); + await removeColumnLineage(page, sourceCol, targetCol); + await page.click('[data-testid="edit-lineage"]'); - await deleteNode(page, apiEndpoint); - await table.delete(apiContext); - await apiEndpoint.delete(apiContext); + await deleteNode(page, apiEndpoint); + await table.delete(apiContext); + await apiEndpoint.delete(apiContext); - await afterAction(); - } -); + await afterAction(); +}); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts index 45efa17e4ef..a21782b6f94 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts @@ -348,6 +348,11 @@ export const assignTag = async ( await searchTags; await page.getByTestId(`tag-${tag}`).click(); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); @@ -393,6 +398,11 @@ export const assignTagToChildren = async ({ (response) => response.request().method() === 'PATCH' ); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); @@ -425,6 +435,11 @@ export const removeTag = async (page: Page, tags: string[]) => { (response) => response.request().method() === 'PATCH' ); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); @@ -467,6 +482,11 @@ export const removeTagsFromChildren = async ({ (response) => response.request().method() === 'PATCH' ); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); @@ -507,6 +527,11 @@ export const assignGlossaryTerm = async ( await searchGlossaryTerm; await page.getByTestId(`tag-${glossaryTerm.fullyQualifiedName}`).click(); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); @@ -549,6 +574,11 @@ export const assignGlossaryTermToChildren = async ({ (response) => response.request().method() === 'PATCH' ); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); @@ -585,6 +615,11 @@ export const removeGlossaryTerm = async ( (response) => response.request().method() === 'PATCH' ); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); @@ -628,6 +663,11 @@ export const removeGlossaryTermFromChildren = async ({ (response) => response.request().method() === 'PATCH' ); + await page.waitForSelector( + '.ant-select-dropdown [data-testid="saveAssociatedTag"]', + { state: 'visible' } + ); + await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); await page.getByTestId('saveAssociatedTag').click(); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index b060e62128d..83d78bd4301 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -867,7 +867,7 @@ export const createDescriptionTaskForGlossary = async ( await assigneeField.click(); const userSearchResponse = page.waitForResponse( - `/api/v1/search/query?q=*${value.assignee}**&index=user_search_index%2Cteam_search_index` + `/api/v1/search/suggest?q=${value.assignee}&index=user_search_index%2Cteam_search_index` ); await assigneeField.fill(value.assignee); await userSearchResponse; @@ -922,7 +922,7 @@ export const createTagTaskForGlossary = async ( ); await assigneeField.click(); const userSearchResponse = page.waitForResponse( - `/api/v1/search/query?q=*${value.assignee}**&index=user_search_index%2Cteam_search_index` + `/api/v1/search/suggest?q=${value.assignee}&index=user_search_index%2Cteam_search_index` ); await assigneeField.fill(value.assignee); await userSearchResponse; diff --git a/openmetadata-ui/src/main/resources/ui/public/locales/en-US/Database/Salesforce.md b/openmetadata-ui/src/main/resources/ui/public/locales/en-US/Database/Salesforce.md index 85285ff207c..516b7edd9c1 100644 --- a/openmetadata-ui/src/main/resources/ui/public/locales/en-US/Database/Salesforce.md +++ b/openmetadata-ui/src/main/resources/ui/public/locales/en-US/Database/Salesforce.md @@ -32,6 +32,16 @@ $$section Salesforce Security Token is required to access the metadata through APIs. You can check out [this doc](https://help.salesforce.com/s/articleView?id=sf.user_security_token.htm&type=5) on how to get the security token. $$ +$$section +### Organization ID $(id="organizationId") + +Salesforce Organization ID is the unique identifier for your Salesforce identity. You can check out [this doc](https://help.salesforce.com/s/articleView?id=000385215&type=1) on how to get the your Salesforce Organization ID. + +**Note**: You need to provide `15` digit organization id in this section. for e.g. `00DIB000004nDEq`, which you can find by following the steps mentioned in above doc (`Salesforce dashboard->Setup->Company Profile->Company Information->Salesforce.com Organization Id`). + +**Note**: If you want to access salesforce metadata without token(only by using organization id), you will need to setup your ip in trusted ip ranges. You can go (`Salesforce dashboard->Setup->Security->Network Access->Trusted IP Ranges`) to configure this. You can check [here](https://help.salesforce.com/s/articleView?id=sf.security_networkaccess.htm&type=5) to configure your ip in trusted ip ranges. +$$ + $$section ### Object Name $(id="sobjectName")