diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js
index 4894fb01ff4..122c94d2a67 100644
--- a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js
+++ b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js
@@ -564,7 +564,12 @@ export const searchEntity = (term, suggestionOverly = true) => {
}
};
-export const visitEntityDetailsPage = (term, serviceName, entity) => {
+export const visitEntityDetailsPage = (
+ term,
+ serviceName,
+ entity,
+ dataTestId
+) => {
interceptURL('GET', '/api/v1/*/name/*', 'getEntityDetails');
interceptURL(
'GET',
@@ -573,7 +578,7 @@ export const visitEntityDetailsPage = (term, serviceName, entity) => {
);
interceptURL('GET', `/api/v1/search/suggest?q=*&index=*`, 'searchQuery');
interceptURL('GET', `/api/v1/search/*`, 'explorePageSearch');
-
+ const id = dataTestId ?? `${serviceName}-${term}`;
// searching term in search box
cy.get('[data-testid="searchBox"]').scrollIntoView().should('be.visible');
cy.get('[data-testid="searchBox"]').type(term);
@@ -581,13 +586,9 @@ export const visitEntityDetailsPage = (term, serviceName, entity) => {
cy.get('[data-testid="suggestion-overlay"]').should('exist');
cy.get('body').then(($body) => {
// checking if requested term is available in search suggestion
- if (
- $body.find(
- `[data-testid="${serviceName}-${term}"] [data-testid="data-name"]`
- ).length
- ) {
+ if ($body.find(`[data-testid="${id}"] [data-testid="data-name"]`).length) {
// if term is available in search suggestion, redirecting to entity details page
- cy.get(`[data-testid="${serviceName}-${term}"] [data-testid="data-name"]`)
+ cy.get(`[data-testid="${id}"] [data-testid="data-name"]`)
.should('be.visible')
.first()
.click();
@@ -601,7 +602,7 @@ export const visitEntityDetailsPage = (term, serviceName, entity) => {
cy.get(`[data-testid="${entity}-tab"]`).should('be.visible');
verifyResponseStatusCode('@explorePageTabSearch', 200);
- cy.get(`[data-testid="${serviceName}-${term}"]`)
+ cy.get(`[data-testid="${id}"]`)
.scrollIntoView()
.should('be.visible')
.click();
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js b/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js
new file mode 100644
index 00000000000..d2fcf0bd662
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 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 { interceptURL, verifyResponseStatusCode } from './common';
+
+export const visitServiceDetailsPage = (service, verifyHeader = true) => {
+ // Click on settings page
+ interceptURL(
+ 'GET',
+ 'api/v1/teams/name/Organization?fields=*',
+ 'getSettingsPage'
+ );
+ cy.get('[data-testid="appbar-item-settings"]').should('be.visible').click();
+ verifyResponseStatusCode('@getSettingsPage', 200);
+ // Services page
+ interceptURL('GET', '/api/v1/services/*', 'getServices');
+
+ cy.get('.ant-menu-title-content')
+ .contains(service.type)
+ .should('be.visible')
+ .click();
+
+ verifyResponseStatusCode('@getServices', 200);
+
+ // click on created service
+ cy.get(`[data-testid="service-name-${service.name}"]`)
+ .should('exist')
+ .should('be.visible')
+ .click();
+
+ if (verifyHeader) {
+ cy.get(`[data-testid="entity-header-name"]`)
+ .should('exist')
+ .should('be.visible')
+ .invoke('text')
+ .then((text) => {
+ expect(text).to.equal(service.name);
+ });
+ }
+
+ verifyResponseStatusCode('@getServices', 200);
+};
+
+export const createDataWithApi = (data, token) => {
+ data.map(({ method, url, body }) => {
+ cy.request({
+ method,
+ url,
+ auth: {
+ bearer: token,
+ },
+ body,
+ });
+ });
+};
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js
index 4ab7b226ce9..5864ba192d1 100644
--- a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js
+++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js
@@ -295,6 +295,7 @@ export const SERVICE_TYPE = {
Dashboard: 'Dashboard',
Pipelines: 'Pipelines',
MLModels: 'ML Models',
+ Storage: 'Storages',
};
export const ENTITIES = {
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/updateDisplayName.constant.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/updateDisplayName.constant.js
new file mode 100644
index 00000000000..2d78b3b585b
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/updateDisplayName.constant.js
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2023 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 { MYDATA_SUMMARY_OPTIONS, SERVICE_TYPE } from './constants';
+
+export const SERVICES = {
+ databaseServices: {
+ type: SERVICE_TYPE.Database,
+ name: 'sample_data',
+ displayName: 'Sample Data',
+ },
+ messagingServices: {
+ type: SERVICE_TYPE.Messaging,
+ name: 'sample_kafka',
+ displayName: 'Sample Kafka',
+ },
+ dashboardServices: {
+ type: SERVICE_TYPE.Dashboard,
+ name: 'sample_looker',
+ displayName: 'Sample Looker',
+ },
+ pipelineServices: {
+ type: SERVICE_TYPE.Pipelines,
+ name: 'sample_airflow',
+ displayName: 'Sample Airflow',
+ },
+ mlmodelServices: {
+ type: SERVICE_TYPE.MLModels,
+ name: 'mlflow_svc',
+ displayName: 'ML Flow Service',
+ },
+ storageServices: {
+ type: SERVICE_TYPE.Storage,
+ name: 's3_storage_sample',
+ displayName: 'Storage Sample Service',
+ },
+};
+
+const DB_SERVICE = SERVICES.databaseServices.name;
+const DATABASE_AND_SCHEMA = {
+ schema: 'shopify',
+ schemaDisplayName: 'Shopify Schema',
+ database: 'ecommerce_db',
+ databaseDisplayName: 'E-Commerce Database',
+};
+
+export const ENTITIES_DISPLAY_NAME = {
+ table: {
+ name: 'dim(shop)',
+ oldDisplayName: 'dim(shop)',
+ displayName: 'Dim Shop Test',
+ entity: MYDATA_SUMMARY_OPTIONS.tables,
+ serviceName: DB_SERVICE,
+ breadcrumb: [
+ DATABASE_AND_SCHEMA.schemaDisplayName,
+ DATABASE_AND_SCHEMA.databaseDisplayName,
+ SERVICES.databaseServices.displayName,
+ ],
+ },
+ topic: {
+ name: 'address_book',
+ oldDisplayName: 'address_book',
+ displayName: 'Kafka Address Book',
+ entity: MYDATA_SUMMARY_OPTIONS.topics,
+ serviceName: SERVICES.messagingServices.name,
+ breadcrumb: [SERVICES.messagingServices.displayName],
+ },
+ dashboard: {
+ name: 'Customers dashboard',
+ oldDisplayName: 'Customers dashboard',
+ displayName: 'Looker Customers Dashboard',
+ entity: MYDATA_SUMMARY_OPTIONS.dashboards,
+ serviceName: SERVICES.dashboardServices.name,
+ breadcrumb: [SERVICES.dashboardServices.displayName],
+ },
+ pipeline: {
+ name: 'dim_address_etl',
+ oldDisplayName: 'dim_address_etl',
+ displayName: 'Dim Address ETL',
+ entity: MYDATA_SUMMARY_OPTIONS.pipelines,
+ serviceName: SERVICES.pipelineServices.name,
+ breadcrumb: [SERVICES.pipelineServices.displayName],
+ },
+ mlmodel: {
+ name: 'eta_predictions',
+ oldDisplayName: 'ETA Predictions',
+ displayName: 'Predictions ETA',
+ entity: MYDATA_SUMMARY_OPTIONS.mlmodels,
+ serviceName: SERVICES.mlmodelServices.name,
+ breadcrumb: [SERVICES.mlmodelServices.displayName],
+ },
+ container: {
+ name: 'departments',
+ oldDisplayName: 'Company departments',
+ displayName: 'Company Departments Test',
+ entity: MYDATA_SUMMARY_OPTIONS.containers,
+ serviceName: SERVICES.storageServices.name,
+ breadcrumb: [SERVICES.storageServices.displayName],
+ },
+};
+export const DASHBOARD_DATA_MODEL = {
+ service: SERVICES.dashboardServices,
+ name: 'Operations View',
+ displayName: 'Operations View Dashboard',
+ breadcrumb: [SERVICES.dashboardServices.displayName],
+};
+
+export const SCHEMA_AND_DATABASE_DISPLAY_NAME = {
+ ...ENTITIES_DISPLAY_NAME.table,
+ ...DATABASE_AND_SCHEMA,
+ schemaBreadcrumb: [
+ DATABASE_AND_SCHEMA.databaseDisplayName,
+ SERVICES.databaseServices.displayName,
+ ],
+ databaseBreadcrumb: [SERVICES.databaseServices.displayName],
+};
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/updateDisplayName.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/updateDisplayName.spec.js
new file mode 100644
index 00000000000..678e2a366dd
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/updateDisplayName.spec.js
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2023 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 {
+ interceptURL,
+ verifyResponseStatusCode,
+ visitEntityDetailsPage,
+} from '../../common/common';
+import { visitServiceDetailsPage } from '../../common/serviceUtils';
+import { MYDATA_SUMMARY_OPTIONS } from '../../constants/constants';
+import {
+ DASHBOARD_DATA_MODEL,
+ ENTITIES_DISPLAY_NAME,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME,
+ SERVICES,
+} from '../../constants/updateDisplayName.constant';
+
+const updateDisplayName = (displayName, apiPath) => {
+ if (apiPath) {
+ interceptURL('PATCH', apiPath, 'patchDisplayName');
+ }
+ cy.get('[data-testid="manage-button"]')
+ .should('exist')
+ .should('be.visible')
+ .click();
+
+ cy.get('[data-menu-id*="delete-button"]')
+ .should('exist')
+ .should('be.visible');
+ cy.get('[data-testid="rename-button"]').should('be.visible').click();
+
+ cy.get('#name').should('be.visible').should('be.disabled');
+ cy.get('#displayName').should('be.visible').should('not.be.disabled').clear();
+ cy.get('.ant-modal-footer').should('contain', 'Cancel');
+ cy.get('[data-testid="save-button"]').should('be.visible').click();
+ cy.get('.ant-modal-body').should('contain', 'Display Name is required');
+ cy.get('#displayName').type(displayName);
+ cy.get('[data-testid="save-button"]').should('be.visible').click();
+
+ if (apiPath) {
+ verifyResponseStatusCode('@patchDisplayName', 200);
+ }
+
+ cy.get('[data-testid="entity-header-display-name"]').should(
+ 'contain',
+ displayName
+ );
+};
+
+describe('Edit displayName for all the entities, services and verify breadcrumb', () => {
+ beforeEach(() => {
+ cy.login();
+ });
+
+ Object.entries(SERVICES).map(([serviceType, service]) => {
+ it(`${service.type}`, () => {
+ visitServiceDetailsPage(service);
+ updateDisplayName(
+ service.displayName,
+ `/api/v1/services/${serviceType}/*`
+ );
+ });
+ });
+
+ it(`dataModel`, () => {
+ interceptURL(
+ 'GET',
+ '/api/v1/dashboard/datamodels?service=*',
+ 'dashboardDataModel'
+ );
+ interceptURL(
+ 'GET',
+ '/api/v1/dashboard/datamodels/name/*',
+ 'dataModelDetails'
+ );
+ visitServiceDetailsPage(
+ {
+ type: DASHBOARD_DATA_MODEL.service.type,
+ name: DASHBOARD_DATA_MODEL.service.displayName,
+ },
+ false
+ );
+ verifyResponseStatusCode('@dashboardDataModel', 200);
+ cy.get('[data-testid="Data Model"]').should('be.visible').click();
+ cy.get('[data-testid="data-models-table"]')
+ .contains(DASHBOARD_DATA_MODEL.name)
+ .click();
+ verifyResponseStatusCode('@dataModelDetails', 200);
+ updateDisplayName(
+ DASHBOARD_DATA_MODEL.displayName,
+ `/api/v1/dashboard/datamodels/*`
+ );
+ DASHBOARD_DATA_MODEL.breadcrumb.map((value) => {
+ cy.get('[data-testid="breadcrumb"]').should('contain', value);
+ });
+ });
+
+ it(`database`, () => {
+ interceptURL('GET', 'api/v1/databases/name/*', 'database');
+ visitEntityDetailsPage(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.name,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.entity
+ );
+ cy.get('[data-testid="breadcrumb"]')
+ .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.database)
+ .click();
+ verifyResponseStatusCode('@database', 200);
+ updateDisplayName(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.databaseDisplayName,
+ `/api/v1/databases/*`
+ );
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.databaseBreadcrumb.map((value) => {
+ cy.get('[data-testid="breadcrumb"]').should('contain', value);
+ });
+ });
+
+ it(`databaseSchema`, () => {
+ interceptURL('GET', 'api/v1/databaseSchemas/name/*', 'databaseSchemas');
+ visitEntityDetailsPage(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.name,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.entity
+ );
+ cy.get('[data-testid="breadcrumb"]')
+ .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.schema)
+ .click();
+ verifyResponseStatusCode('@databaseSchemas', 200);
+ updateDisplayName(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.schemaDisplayName,
+ `/api/v1/databaseSchemas/*`
+ );
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.schemaBreadcrumb.map((value) => {
+ cy.get('[data-testid="breadcrumb"]').should('contain', value);
+ });
+ });
+
+ Object.values(ENTITIES_DISPLAY_NAME).map((entity) => {
+ it(`${entity.entity}`, () => {
+ visitEntityDetailsPage(entity.name, entity.serviceName, entity.entity);
+ updateDisplayName(entity.displayName, `/api/v1/${entity.entity}/*`);
+ entity.breadcrumb.map((value) => {
+ cy.get('[data-testid="breadcrumb"]').should('contain', value);
+ });
+ });
+ });
+});
+
+describe('Cleanup', () => {
+ beforeEach(() => {
+ cy.login();
+ });
+
+ Object.values(ENTITIES_DISPLAY_NAME).map((entity) => {
+ it(`${entity.entity}`, () => {
+ if (entity.entity === MYDATA_SUMMARY_OPTIONS.dashboards) {
+ visitEntityDetailsPage(
+ entity.displayName,
+ entity.serviceName,
+ entity.entity
+ );
+ } else {
+ visitEntityDetailsPage(entity.name, entity.serviceName, entity.entity);
+ }
+ updateDisplayName(entity.oldDisplayName, `/api/v1/${entity.entity}/*`);
+ });
+ });
+
+ it(`databaseSchema`, () => {
+ interceptURL('GET', 'api/v1/databaseSchemas/name/*', 'databaseSchemas');
+ visitEntityDetailsPage(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.name,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.entity
+ );
+ cy.get('[data-testid="breadcrumb"]')
+ .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.schemaDisplayName)
+ .click();
+ verifyResponseStatusCode('@databaseSchemas', 200);
+ updateDisplayName(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.schema,
+ `/api/v1/databaseSchemas/*`
+ );
+ });
+
+ it(`database`, () => {
+ interceptURL('GET', 'api/v1/databases/name/*', 'database');
+ visitEntityDetailsPage(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.name,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName,
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.entity
+ );
+ cy.get('[data-testid="breadcrumb"]')
+ .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.databaseDisplayName)
+ .click();
+ verifyResponseStatusCode('@database', 200);
+ updateDisplayName(
+ SCHEMA_AND_DATABASE_DISPLAY_NAME.database,
+ `/api/v1/databases/*`
+ );
+ });
+
+ it(`dataModel`, () => {
+ interceptURL(
+ 'GET',
+ '/api/v1/dashboard/datamodels?service=*',
+ 'dashboardDataModel'
+ );
+ interceptURL(
+ 'GET',
+ '/api/v1/dashboard/datamodels/name/*',
+ 'dataModelDetails'
+ );
+ visitServiceDetailsPage(
+ {
+ type: DASHBOARD_DATA_MODEL.service.type,
+ name: DASHBOARD_DATA_MODEL.service.displayName,
+ },
+ false
+ );
+ verifyResponseStatusCode('@dashboardDataModel', 200);
+ cy.get('[data-testid="Data Model"]').should('be.visible').click();
+ cy.get('[data-testid="data-models-table"]')
+ .contains(DASHBOARD_DATA_MODEL.name)
+ .click();
+ verifyResponseStatusCode('@dataModelDetails', 200);
+ updateDisplayName(
+ DASHBOARD_DATA_MODEL.displayName,
+ `/api/v1/dashboard/datamodels/*`
+ );
+ });
+
+ Object.entries(SERVICES).map(([serviceType, service]) => {
+ it(`${service.type}`, () => {
+ visitServiceDetailsPage(
+ {
+ type: service.type,
+ name: service.displayName,
+ },
+ false
+ );
+ updateDisplayName(service.name, `/api/v1/services/${serviceType}/*`);
+ });
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.spec.js
similarity index 100%
rename from openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.js
rename to openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.spec.js
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx
index 1103c8cc051..b2382512ada 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx
@@ -68,7 +68,7 @@ const EntityNameModal: React.FC = ({
onCancel={onCancel}>
= ({
/>