mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-24 15:25:10 +00:00
UI : Added tags at schema Level (#10471)
* Added tags at schema Level * Add task handling for Database Schema * added cypress and unit test * Changes as per comments --------- Co-authored-by: Mohit Yadav <105265192+mohityadav766@users.noreply.github.com> Co-authored-by: mohitdeuex <mohit.y@deuexsolutions.com>
This commit is contained in:
parent
0f9c2c2164
commit
c0fe8ec871
@ -19,6 +19,7 @@ import static org.openmetadata.schema.type.Relationship.CREATED;
|
|||||||
import static org.openmetadata.schema.type.Relationship.IS_ABOUT;
|
import static org.openmetadata.schema.type.Relationship.IS_ABOUT;
|
||||||
import static org.openmetadata.schema.type.Relationship.REPLIED_TO;
|
import static org.openmetadata.schema.type.Relationship.REPLIED_TO;
|
||||||
import static org.openmetadata.service.Entity.DASHBOARD;
|
import static org.openmetadata.service.Entity.DASHBOARD;
|
||||||
|
import static org.openmetadata.service.Entity.DATABASE_SCHEMA;
|
||||||
import static org.openmetadata.service.Entity.FIELD_DESCRIPTION;
|
import static org.openmetadata.service.Entity.FIELD_DESCRIPTION;
|
||||||
import static org.openmetadata.service.Entity.PIPELINE;
|
import static org.openmetadata.service.Entity.PIPELINE;
|
||||||
import static org.openmetadata.service.Entity.TABLE;
|
import static org.openmetadata.service.Entity.TABLE;
|
||||||
@ -60,6 +61,7 @@ import org.openmetadata.schema.api.feed.EntityLinkThreadCount;
|
|||||||
import org.openmetadata.schema.api.feed.ResolveTask;
|
import org.openmetadata.schema.api.feed.ResolveTask;
|
||||||
import org.openmetadata.schema.api.feed.ThreadCount;
|
import org.openmetadata.schema.api.feed.ThreadCount;
|
||||||
import org.openmetadata.schema.entity.data.Dashboard;
|
import org.openmetadata.schema.entity.data.Dashboard;
|
||||||
|
import org.openmetadata.schema.entity.data.DatabaseSchema;
|
||||||
import org.openmetadata.schema.entity.data.Pipeline;
|
import org.openmetadata.schema.entity.data.Pipeline;
|
||||||
import org.openmetadata.schema.entity.data.Table;
|
import org.openmetadata.schema.entity.data.Table;
|
||||||
import org.openmetadata.schema.entity.data.Topic;
|
import org.openmetadata.schema.entity.data.Topic;
|
||||||
@ -342,8 +344,33 @@ public class FeedRepository {
|
|||||||
patch = JsonUtils.getJsonPatch(oldJson, updatedEntityJson);
|
patch = JsonUtils.getJsonPatch(oldJson, updatedEntityJson);
|
||||||
repository.patch(uriInfo, pipeline.getId(), user, patch);
|
repository.patch(uriInfo, pipeline.getId(), user, patch);
|
||||||
break;
|
break;
|
||||||
default:
|
case DATABASE_SCHEMA:
|
||||||
|
DatabaseSchema databaseSchema = JsonUtils.readValue(json, DatabaseSchema.class);
|
||||||
|
oldJson = JsonUtils.pojoToJson(databaseSchema);
|
||||||
|
if (entityLink.getFieldName() != null) {
|
||||||
|
if (descriptionTasks.contains(taskType) && entityLink.getFieldName().equals(FIELD_DESCRIPTION)) {
|
||||||
|
databaseSchema.setDescription(newValue);
|
||||||
|
} else if (tagTasks.contains(taskType) && entityLink.getFieldName().equals("tags")) {
|
||||||
|
List<TagLabel> tags = JsonUtils.readObjects(newValue, TagLabel.class);
|
||||||
|
databaseSchema.setTags(tags);
|
||||||
|
} else {
|
||||||
|
// Not supported
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(UNSUPPORTED_FIELD_NAME_FOR_TASK, entityLink.getFieldName(), task.getType()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not supported
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"The Entity link with no field name - %s is not supported for %s task.",
|
||||||
|
entityLink, task.getType()));
|
||||||
|
}
|
||||||
|
updatedEntityJson = JsonUtils.pojoToJson(databaseSchema);
|
||||||
|
patch = JsonUtils.getJsonPatch(oldJson, updatedEntityJson);
|
||||||
|
repository.patch(uriInfo, databaseSchema.getId(), user, patch);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Task is not supported for the Data Asset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,7 @@ export const SEARCH_ENTITY_TABLE = {
|
|||||||
term: 'fact_session',
|
term: 'fact_session',
|
||||||
entity: MYDATA_SUMMARY_OPTIONS.tables,
|
entity: MYDATA_SUMMARY_OPTIONS.tables,
|
||||||
serviceName: 'sample_data',
|
serviceName: 'sample_data',
|
||||||
|
schemaName: 'shopify',
|
||||||
},
|
},
|
||||||
table_3: {
|
table_3: {
|
||||||
term: 'raw_product_catalog',
|
term: 'raw_product_catalog',
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
descriptionBox,
|
descriptionBox,
|
||||||
interceptURL,
|
interceptURL,
|
||||||
verifyResponseStatusCode,
|
verifyResponseStatusCode,
|
||||||
|
visitEntityDetailsPage,
|
||||||
} from '../../common/common';
|
} from '../../common/common';
|
||||||
import {
|
import {
|
||||||
DELETE_TERM,
|
DELETE_TERM,
|
||||||
@ -155,6 +156,98 @@ describe('Tags page should work', () => {
|
|||||||
addNewTagToEntity(entity, `${NEW_TAG_CATEGORY.name}.${NEW_TAG.name}`);
|
addNewTagToEntity(entity, `${NEW_TAG_CATEGORY.name}.${NEW_TAG.name}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Add tag at DatabaseSchema level should work', () => {
|
||||||
|
const entity = SEARCH_ENTITY_TABLE.table_2;
|
||||||
|
const term = `${NEW_TAG_CATEGORY.name}.${NEW_TAG.name}`;
|
||||||
|
const term2 = 'PersonalData.Personal';
|
||||||
|
visitEntityDetailsPage(entity.term, entity.serviceName, entity.entity);
|
||||||
|
|
||||||
|
cy.get('[data-testid="breadcrumb-link"]')
|
||||||
|
.should('be.visible')
|
||||||
|
.within(() => {
|
||||||
|
cy.contains(entity.schemaName).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-testid="tags"] > [data-testid="add-tag"]')
|
||||||
|
.should('be.visible')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.get('[data-testid="tag-selector"] input')
|
||||||
|
.should('be.visible')
|
||||||
|
.type(term);
|
||||||
|
|
||||||
|
cy.get('.ant-select-item-option-content')
|
||||||
|
.contains(term)
|
||||||
|
.should('be.visible')
|
||||||
|
.click();
|
||||||
|
cy.get(
|
||||||
|
'[data-testid="tags-wrapper"] > [data-testid="tag-container"]'
|
||||||
|
).contains(term);
|
||||||
|
interceptURL('PATCH', '/api/v1/databaseSchemas/*', 'addTags');
|
||||||
|
cy.get('[data-testid="saveAssociatedTag"]').should('be.visible').click();
|
||||||
|
verifyResponseStatusCode('@addTags', 200);
|
||||||
|
cy.get('[data-testid="entity-tags"]')
|
||||||
|
.scrollIntoView()
|
||||||
|
.should('be.visible')
|
||||||
|
.contains(term);
|
||||||
|
|
||||||
|
cy.get('[data-testid="tag-thread-count"]').should('exist').contains(1);
|
||||||
|
|
||||||
|
// Create task to add tags
|
||||||
|
interceptURL('POST', '/api/v1/feed', 'taskCreated');
|
||||||
|
cy.get('[data-testid="request-entity-tags"] > [data-testid="image"]')
|
||||||
|
.should('exist')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.get(
|
||||||
|
'[data-testid="select-tags"] > .ant-select-selector > .ant-select-selection-overflow'
|
||||||
|
)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.type(term2);
|
||||||
|
cy.get('.ant-select-item-option-content').contains(term2).click();
|
||||||
|
|
||||||
|
cy.get('[data-testid="tags-label"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-testid="submit-test"]').should('be.visible').click();
|
||||||
|
// Accept the tag suggestion which is created
|
||||||
|
cy.get('.ant-btn-compact-first-item')
|
||||||
|
.should('be.visible')
|
||||||
|
.contains('Accept Suggestion')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
verifyResponseStatusCode('@taskCreated', 201);
|
||||||
|
|
||||||
|
cy.get('[data-testid="entity-tags"]')
|
||||||
|
.scrollIntoView()
|
||||||
|
.should('be.visible')
|
||||||
|
.contains(term2);
|
||||||
|
|
||||||
|
cy.get('[data-testid="tag-thread-count"]').should('exist').contains(2);
|
||||||
|
|
||||||
|
cy.get('[data-testid="edit-button"]').should('exist').click();
|
||||||
|
|
||||||
|
// Remove all added tags
|
||||||
|
cy.get('.ant-select-selection-item-remove')
|
||||||
|
.eq(0)
|
||||||
|
.should('be.visible')
|
||||||
|
.click();
|
||||||
|
cy.get('.ant-select-selection-item-remove')
|
||||||
|
.eq(0)
|
||||||
|
.should('be.visible')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
interceptURL('PATCH', '/api/v1/databaseSchemas/*', 'removeTags');
|
||||||
|
cy.get('[data-testid="saveAssociatedTag"]').should('be.visible').click();
|
||||||
|
verifyResponseStatusCode('@removeTags', 200);
|
||||||
|
|
||||||
|
cy.get('[data-testid="tags"] > [data-testid="add-tag"]').should(
|
||||||
|
'be.visible'
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.get('[data-testid="tag-thread-count"]').should('exist').contains(3);
|
||||||
|
});
|
||||||
|
|
||||||
it('Check Usage of tag and it should redirect to explore page with tags filter', () => {
|
it('Check Usage of tag and it should redirect to explore page with tags filter', () => {
|
||||||
interceptURL(
|
interceptURL(
|
||||||
'GET',
|
'GET',
|
||||||
|
|||||||
@ -83,6 +83,8 @@ interface Props {
|
|||||||
currentOwner?: Dashboard['owner'];
|
currentOwner?: Dashboard['owner'];
|
||||||
removeTier?: () => void;
|
removeTier?: () => void;
|
||||||
onRestoreEntity?: () => void;
|
onRestoreEntity?: () => void;
|
||||||
|
allowSoftDelete?: boolean;
|
||||||
|
isRecursiveDelete?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EntityPageInfo = ({
|
const EntityPageInfo = ({
|
||||||
@ -114,6 +116,8 @@ const EntityPageInfo = ({
|
|||||||
entityFieldTasks,
|
entityFieldTasks,
|
||||||
removeTier,
|
removeTier,
|
||||||
onRestoreEntity,
|
onRestoreEntity,
|
||||||
|
isRecursiveDelete = false,
|
||||||
|
allowSoftDelete,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const tagThread = entityFieldThreads?.[0];
|
const tagThread = entityFieldThreads?.[0];
|
||||||
@ -443,13 +447,18 @@ const EntityPageInfo = ({
|
|||||||
) : null}
|
) : null}
|
||||||
{!isVersionSelected && (
|
{!isVersionSelected && (
|
||||||
<ManageButton
|
<ManageButton
|
||||||
allowSoftDelete={!deleted}
|
allowSoftDelete={
|
||||||
|
entityType === EntityType.DATABASE_SCHEMA
|
||||||
|
? allowSoftDelete
|
||||||
|
: !deleted
|
||||||
|
}
|
||||||
canDelete={canDelete}
|
canDelete={canDelete}
|
||||||
deleted={deleted}
|
deleted={deleted}
|
||||||
entityFQN={entityFqn}
|
entityFQN={entityFqn}
|
||||||
entityId={entityId}
|
entityId={entityId}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
entityType={entityType}
|
entityType={entityType}
|
||||||
|
isRecursiveDelete={isRecursiveDelete}
|
||||||
onAnnouncementClick={() => setIsAnnouncementDrawer(true)}
|
onAnnouncementClick={() => setIsAnnouncementDrawer(true)}
|
||||||
onRestoreEntity={onRestoreEntity}
|
onRestoreEntity={onRestoreEntity}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -11,19 +11,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Card, Col, Row, Skeleton, Space, Table as TableAntd } from 'antd';
|
import { Card, Col, Row, Skeleton, Table as TableAntd } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import ActivityFeedList from 'components/ActivityFeed/ActivityFeedList/ActivityFeedList';
|
import ActivityFeedList from 'components/ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||||
import ActivityThreadPanel from 'components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
import ActivityThreadPanel from 'components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||||
import Description from 'components/common/description/Description';
|
import Description from 'components/common/description/Description';
|
||||||
import ManageButton from 'components/common/entityPageInfo/ManageButton/ManageButton';
|
import EntityPageInfo from 'components/common/entityPageInfo/EntityPageInfo';
|
||||||
import EntitySummaryDetails from 'components/common/EntitySummaryDetails/EntitySummaryDetails';
|
|
||||||
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||||
import NextPrevious from 'components/common/next-previous/NextPrevious';
|
import NextPrevious from 'components/common/next-previous/NextPrevious';
|
||||||
import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer';
|
import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer';
|
||||||
import TabsPane from 'components/common/TabsPane/TabsPane';
|
import TabsPane from 'components/common/TabsPane/TabsPane';
|
||||||
import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component';
|
|
||||||
import { TitleBreadcrumbProps } from 'components/common/title-breadcrumb/title-breadcrumb.interface';
|
import { TitleBreadcrumbProps } from 'components/common/title-breadcrumb/title-breadcrumb.interface';
|
||||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||||
import Loader from 'components/Loader/Loader';
|
import Loader from 'components/Loader/Loader';
|
||||||
@ -33,9 +31,10 @@ import {
|
|||||||
ResourceEntity,
|
ResourceEntity,
|
||||||
} from 'components/PermissionProvider/PermissionProvider.interface';
|
} from 'components/PermissionProvider/PermissionProvider.interface';
|
||||||
import { compare, Operation } from 'fast-json-patch';
|
import { compare, Operation } from 'fast-json-patch';
|
||||||
|
import { TagLabel } from 'generated/type/tagLabel';
|
||||||
import { isUndefined, startCase, toNumber } from 'lodash';
|
import { isUndefined, startCase, toNumber } from 'lodash';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { ExtraInfo } from 'Models';
|
import { EntityTags, ExtraInfo } from 'Models';
|
||||||
import React, {
|
import React, {
|
||||||
Fragment,
|
Fragment,
|
||||||
FunctionComponent,
|
FunctionComponent,
|
||||||
@ -106,7 +105,11 @@ import {
|
|||||||
serviceTypeLogo,
|
serviceTypeLogo,
|
||||||
} from '../../utils/ServiceUtils';
|
} from '../../utils/ServiceUtils';
|
||||||
import { getErrorText } from '../../utils/StringsUtils';
|
import { getErrorText } from '../../utils/StringsUtils';
|
||||||
import { getEntityLink } from '../../utils/TableUtils';
|
import {
|
||||||
|
getEntityLink,
|
||||||
|
getTagsWithoutTier,
|
||||||
|
getTierTags,
|
||||||
|
} from '../../utils/TableUtils';
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
|
|
||||||
const DatabaseSchemaPage: FunctionComponent = () => {
|
const DatabaseSchemaPage: FunctionComponent = () => {
|
||||||
@ -157,6 +160,9 @@ const DatabaseSchemaPage: FunctionComponent = () => {
|
|||||||
const [databaseSchemaPermission, setDatabaseSchemaPermission] =
|
const [databaseSchemaPermission, setDatabaseSchemaPermission] =
|
||||||
useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION);
|
useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION);
|
||||||
|
|
||||||
|
const [tags, setTags] = useState<Array<EntityTags>>([]);
|
||||||
|
const [tier, setTier] = useState<TagLabel>();
|
||||||
|
|
||||||
const fetchDatabaseSchemaPermission = async () => {
|
const fetchDatabaseSchemaPermission = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
@ -253,7 +259,11 @@ const DatabaseSchemaPage: FunctionComponent = () => {
|
|||||||
|
|
||||||
const getDetailsByFQN = () => {
|
const getDetailsByFQN = () => {
|
||||||
setIsSchemaDetailsLoading(true);
|
setIsSchemaDetailsLoading(true);
|
||||||
getDatabaseSchemaDetailsByFQN(databaseSchemaFQN, ['owner', 'usageSummary'])
|
getDatabaseSchemaDetailsByFQN(databaseSchemaFQN, [
|
||||||
|
'owner',
|
||||||
|
'usageSummary',
|
||||||
|
'tags',
|
||||||
|
])
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
const {
|
const {
|
||||||
@ -263,11 +273,14 @@ const DatabaseSchemaPage: FunctionComponent = () => {
|
|||||||
service,
|
service,
|
||||||
serviceType,
|
serviceType,
|
||||||
database,
|
database,
|
||||||
|
tags,
|
||||||
} = res;
|
} = res;
|
||||||
setDatabaseSchema(res);
|
setDatabaseSchema(res);
|
||||||
setDescription(schemaDescription);
|
setDescription(schemaDescription);
|
||||||
setDatabaseSchemaId(id);
|
setDatabaseSchemaId(id);
|
||||||
setDatabaseSchemaName(name);
|
setDatabaseSchemaName(name);
|
||||||
|
setTags(getTagsWithoutTier(tags || []));
|
||||||
|
setTier(getTierTags(tags ?? []));
|
||||||
setSlashedTableName([
|
setSlashedTableName([
|
||||||
{
|
{
|
||||||
name: startCase(ServiceCategory.DATABASE_SERVICES),
|
name: startCase(ServiceCategory.DATABASE_SERVICES),
|
||||||
@ -470,6 +483,25 @@ const DatabaseSchemaPage: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onTagUpdate = async (selectedTags?: Array<EntityTags>) => {
|
||||||
|
if (selectedTags) {
|
||||||
|
const updatedTags = [...(tier ? [tier] : []), ...selectedTags];
|
||||||
|
const updatedData = { ...databaseSchema, tags: updatedTags };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await saveUpdatedDatabaseSchemaData(
|
||||||
|
updatedData as DatabaseSchema
|
||||||
|
);
|
||||||
|
setDatabaseSchema(res);
|
||||||
|
setTags(getTagsWithoutTier(res.tags || []));
|
||||||
|
setTier(getTierTags(res.tags ?? []));
|
||||||
|
getEntityFeedCount();
|
||||||
|
} catch (error) {
|
||||||
|
showErrorToast(error as AxiosError, t('server.api-error'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const fetchActivityFeed = (after?: string) => {
|
const fetchActivityFeed = (after?: string) => {
|
||||||
setIsentityThreadLoading(true);
|
setIsentityThreadLoading(true);
|
||||||
getAllFeeds(
|
getAllFeeds(
|
||||||
@ -711,40 +743,43 @@ const DatabaseSchemaPage: FunctionComponent = () => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<Space align="center" className="justify-between w-full">
|
<EntityPageInfo
|
||||||
<TitleBreadcrumb titleLinks={slashedTableName} />
|
isRecursiveDelete
|
||||||
<ManageButton
|
allowSoftDelete={false}
|
||||||
isRecursiveDelete
|
canDelete={databaseSchemaPermission.Delete}
|
||||||
allowSoftDelete={false}
|
currentOwner={databaseSchema?.owner}
|
||||||
canDelete={databaseSchemaPermission.Delete}
|
entityFieldThreads={getEntityFieldThreadCounts(
|
||||||
entityFQN={databaseSchemaFQN}
|
EntityField.TAGS,
|
||||||
entityId={databaseSchemaId}
|
entityFieldThreadCount
|
||||||
entityName={databaseSchemaName}
|
)}
|
||||||
entityType={EntityType.DATABASE_SCHEMA}
|
entityFqn={databaseSchemaFQN}
|
||||||
/>
|
entityId={databaseSchemaId}
|
||||||
</Space>
|
entityName={databaseSchemaName}
|
||||||
</Col>
|
entityType={EntityType.DATABASE_SCHEMA}
|
||||||
<Col span={24}>
|
extraInfo={extraInfo}
|
||||||
{extraInfo.map((info, index) => (
|
followersList={[]}
|
||||||
<Space key={index}>
|
isTagEditable={
|
||||||
<EntitySummaryDetails
|
databaseSchemaPermission.EditAll ||
|
||||||
currentOwner={databaseSchema?.owner}
|
databaseSchemaPermission.EditTags
|
||||||
data={info}
|
}
|
||||||
removeOwner={
|
removeOwner={
|
||||||
databaseSchemaPermission.EditOwner ||
|
databaseSchemaPermission.EditOwner ||
|
||||||
databaseSchemaPermission.EditAll
|
databaseSchemaPermission.EditAll
|
||||||
? handleRemoveOwner
|
? handleRemoveOwner
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
updateOwner={
|
tags={tags}
|
||||||
databaseSchemaPermission.EditOwner ||
|
tagsHandler={onTagUpdate}
|
||||||
databaseSchemaPermission.EditAll
|
tier={tier}
|
||||||
? handleUpdateOwner
|
titleLinks={slashedTableName}
|
||||||
: undefined
|
updateOwner={
|
||||||
}
|
databaseSchemaPermission.EditOwner ||
|
||||||
/>
|
databaseSchemaPermission.EditAll
|
||||||
</Space>
|
? handleUpdateOwner
|
||||||
))}
|
: undefined
|
||||||
|
}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col data-testid="description-container" span={24}>
|
<Col data-testid="description-container" span={24}>
|
||||||
<Description
|
<Description
|
||||||
|
|||||||
@ -46,14 +46,6 @@ jest.mock('components/containers/PageContainerV1', () =>
|
|||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
jest.mock('components/common/title-breadcrumb/title-breadcrumb.component', () =>
|
|
||||||
jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementation(() => (
|
|
||||||
<div data-testid="TitleBreadcrumb">titleBreadcrumb</div>
|
|
||||||
))
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.mock('components/common/TabsPane/TabsPane', () =>
|
jest.mock('components/common/TabsPane/TabsPane', () =>
|
||||||
jest.fn().mockImplementation(() => <div data-testid="TabsPane">TabsPane</div>)
|
jest.fn().mockImplementation(() => <div data-testid="TabsPane">TabsPane</div>)
|
||||||
);
|
);
|
||||||
@ -81,19 +73,12 @@ jest.mock('components/common/error-with-placeholder/ErrorPlaceHolder', () =>
|
|||||||
<div data-testid="ErrorPlaceHolder">{children}</div>
|
<div data-testid="ErrorPlaceHolder">{children}</div>
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
jest.mock('components/common/EntitySummaryDetails/EntitySummaryDetails', () =>
|
|
||||||
jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementation(() => (
|
|
||||||
<div data-testid="EntitySummaryDetails">EntitySummaryDetails</div>
|
|
||||||
))
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.mock('components/common/entityPageInfo/ManageButton/ManageButton', () =>
|
jest.mock('components/common/entityPageInfo/EntityPageInfo', () =>
|
||||||
jest
|
jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(() => (
|
.mockImplementation(() => (
|
||||||
<div data-testid="ManageButton">ManageButton</div>
|
<div data-testid="entityPageInfo">EntityPageInfo</div>
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -205,15 +190,11 @@ describe('Tests for DatabaseSchemaPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const pageContainer = await screen.findByTestId('PageContainer');
|
const pageContainer = await screen.findByTestId('PageContainer');
|
||||||
const titleBreadcrumb = await screen.findByTestId('TitleBreadcrumb');
|
const entityPageInfo = await screen.findByTestId('entityPageInfo');
|
||||||
const tabsPane = await screen.findByTestId('TabsPane');
|
const tabsPane = await screen.findByTestId('TabsPane');
|
||||||
const richTextEditorPreviewer = await screen.findAllByTestId(
|
const richTextEditorPreviewer = await screen.findAllByTestId(
|
||||||
'RichTextEditorPreviewer'
|
'RichTextEditorPreviewer'
|
||||||
);
|
);
|
||||||
const entitySummaryDetails = await screen.findByTestId(
|
|
||||||
'EntitySummaryDetails'
|
|
||||||
);
|
|
||||||
const manageButton = await screen.findByTestId('ManageButton');
|
|
||||||
const description = await screen.findByTestId('Description');
|
const description = await screen.findByTestId('Description');
|
||||||
const nextPrevious = await screen.findByTestId('NextPrevious');
|
const nextPrevious = await screen.findByTestId('NextPrevious');
|
||||||
const databaseSchemaTable = await screen.findByTestId(
|
const databaseSchemaTable = await screen.findByTestId(
|
||||||
@ -221,11 +202,9 @@ describe('Tests for DatabaseSchemaPage', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(pageContainer).toBeInTheDocument();
|
expect(pageContainer).toBeInTheDocument();
|
||||||
expect(titleBreadcrumb).toBeInTheDocument();
|
expect(entityPageInfo).toBeInTheDocument();
|
||||||
expect(tabsPane).toBeInTheDocument();
|
expect(tabsPane).toBeInTheDocument();
|
||||||
expect(richTextEditorPreviewer).toHaveLength(10);
|
expect(richTextEditorPreviewer).toHaveLength(10);
|
||||||
expect(entitySummaryDetails).toBeInTheDocument();
|
|
||||||
expect(manageButton).toBeInTheDocument();
|
|
||||||
expect(description).toBeInTheDocument();
|
expect(description).toBeInTheDocument();
|
||||||
expect(nextPrevious).toBeInTheDocument();
|
expect(nextPrevious).toBeInTheDocument();
|
||||||
expect(databaseSchemaTable).toBeInTheDocument();
|
expect(databaseSchemaTable).toBeInTheDocument();
|
||||||
|
|||||||
@ -11,13 +11,20 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { DatabaseSchema } from 'generated/entity/data/databaseSchema';
|
||||||
import { Dashboard } from '../../generated/entity/data/dashboard';
|
import { Dashboard } from '../../generated/entity/data/dashboard';
|
||||||
import { Mlmodel } from '../../generated/entity/data/mlmodel';
|
import { Mlmodel } from '../../generated/entity/data/mlmodel';
|
||||||
import { Pipeline } from '../../generated/entity/data/pipeline';
|
import { Pipeline } from '../../generated/entity/data/pipeline';
|
||||||
import { Table } from '../../generated/entity/data/table';
|
import { Table } from '../../generated/entity/data/table';
|
||||||
import { Topic } from '../../generated/entity/data/topic';
|
import { Topic } from '../../generated/entity/data/topic';
|
||||||
|
|
||||||
export type EntityData = Table | Topic | Dashboard | Pipeline | Mlmodel;
|
export type EntityData =
|
||||||
|
| Table
|
||||||
|
| Topic
|
||||||
|
| Dashboard
|
||||||
|
| Pipeline
|
||||||
|
| Mlmodel
|
||||||
|
| DatabaseSchema;
|
||||||
|
|
||||||
export interface Option {
|
export interface Option {
|
||||||
label: string;
|
label: string;
|
||||||
|
|||||||
@ -60,3 +60,6 @@ export const getQueryStringForSchemaTables = (
|
|||||||
schemaName: DatabaseSchema
|
schemaName: DatabaseSchema
|
||||||
) =>
|
) =>
|
||||||
`(service.name:${serviceName.name}) AND (database.name:${databaseName.name}) AND (databaseSchema.name:${schemaName.name})`;
|
`(service.name:${serviceName.name}) AND (database.name:${databaseName.name}) AND (databaseSchema.name:${schemaName.name})`;
|
||||||
|
|
||||||
|
export const defaultFields = `${TabSpecificField.TAGS}, ${TabSpecificField.OWNER},
|
||||||
|
${TabSpecificField.USAGE_SUMMARY}`;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import {
|
|||||||
TaskActionMode,
|
TaskActionMode,
|
||||||
} from 'pages/TasksPage/TasksPage.interface';
|
} from 'pages/TasksPage/TasksPage.interface';
|
||||||
import { getDashboardByFqn } from 'rest/dashboardAPI';
|
import { getDashboardByFqn } from 'rest/dashboardAPI';
|
||||||
|
import { getDatabaseSchemaDetailsByFQN } from 'rest/databaseAPI';
|
||||||
import { getUserSuggestions } from 'rest/miscAPI';
|
import { getUserSuggestions } from 'rest/miscAPI';
|
||||||
import { getMlModelByFQN } from 'rest/mlModelAPI';
|
import { getMlModelByFQN } from 'rest/mlModelAPI';
|
||||||
import { getPipelineByFqn } from 'rest/pipelineAPI';
|
import { getPipelineByFqn } from 'rest/pipelineAPI';
|
||||||
@ -42,6 +43,7 @@ import { Column, Table } from '../generated/entity/data/table';
|
|||||||
import { TaskType } from '../generated/entity/feed/thread';
|
import { TaskType } from '../generated/entity/feed/thread';
|
||||||
import { getEntityName, getPartialNameFromTableFQN } from './CommonUtils';
|
import { getEntityName, getPartialNameFromTableFQN } from './CommonUtils';
|
||||||
import { defaultFields as DashboardFields } from './DashboardDetailsUtils';
|
import { defaultFields as DashboardFields } from './DashboardDetailsUtils';
|
||||||
|
import { defaultFields as DatabaseSchemaFields } from './DatabaseSchemaDetailsUtils';
|
||||||
import { defaultFields as TableFields } from './DatasetDetailsUtils';
|
import { defaultFields as TableFields } from './DatasetDetailsUtils';
|
||||||
import { defaultFields as MlModelFields } from './MlModelDetailsUtils';
|
import { defaultFields as MlModelFields } from './MlModelDetailsUtils';
|
||||||
import { defaultFields as PipelineFields } from './PipelineDetailsUtils';
|
import { defaultFields as PipelineFields } from './PipelineDetailsUtils';
|
||||||
@ -185,6 +187,7 @@ export const TASK_ENTITIES = [
|
|||||||
EntityType.TOPIC,
|
EntityType.TOPIC,
|
||||||
EntityType.PIPELINE,
|
EntityType.PIPELINE,
|
||||||
EntityType.MLMODEL,
|
EntityType.MLMODEL,
|
||||||
|
EntityType.DATABASE_SCHEMA,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getBreadCrumbList = (
|
export const getBreadCrumbList = (
|
||||||
@ -254,6 +257,14 @@ export const getBreadCrumbList = (
|
|||||||
return [service(ServiceCategory.ML_MODEL_SERVICES), activeEntity];
|
return [service(ServiceCategory.ML_MODEL_SERVICES), activeEntity];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case EntityType.DATABASE_SCHEMA: {
|
||||||
|
return [
|
||||||
|
service(ServiceCategory.DATABASE_SERVICES),
|
||||||
|
database,
|
||||||
|
activeEntity,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -306,6 +317,15 @@ export const fetchEntityDetail = (
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EntityType.DATABASE_SCHEMA:
|
||||||
|
getDatabaseSchemaDetailsByFQN(entityFQN, DatabaseSchemaFields)
|
||||||
|
.then((res) => {
|
||||||
|
setEntityData(res);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => showErrorToast(err));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user