mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-28 10:56:02 +00:00
* Supported DataModel in Dashboard Page * url fqn changes * Support Activity tab for DataModel Entity * Remove dataModel resource descriptor * Fix tasks for dashboard data models * changes as per comments * minor fix * changes as per comments and minor improvements --------- Co-authored-by: Nahuel Verdugo Revigliono <nahuel@getcollate.io>
This commit is contained in:
parent
27984c25f3
commit
c997d8c80b
@ -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.DASHBOARD_DATA_MODEL;
|
||||||
import static org.openmetadata.service.Entity.DATABASE_SCHEMA;
|
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;
|
||||||
@ -61,6 +62,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.DashboardDataModel;
|
||||||
import org.openmetadata.schema.entity.data.DatabaseSchema;
|
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;
|
||||||
@ -312,6 +314,50 @@ public class FeedRepository {
|
|||||||
patch = JsonUtils.getJsonPatch(oldJson, updatedEntityJson);
|
patch = JsonUtils.getJsonPatch(oldJson, updatedEntityJson);
|
||||||
repository.patch(uriInfo, dashboard.getId(), user, patch);
|
repository.patch(uriInfo, dashboard.getId(), user, patch);
|
||||||
break;
|
break;
|
||||||
|
case DASHBOARD_DATA_MODEL:
|
||||||
|
DashboardDataModel dashboardDataModel = JsonUtils.readValue(json, DashboardDataModel.class);
|
||||||
|
oldJson = JsonUtils.pojoToJson(dashboardDataModel);
|
||||||
|
if (entityLink.getFieldName() != null) {
|
||||||
|
if (entityLink.getFieldName().equals("columns")) {
|
||||||
|
Optional<Column> col =
|
||||||
|
dashboardDataModel.getColumns().stream()
|
||||||
|
.filter(c -> c.getName().equals(entityLink.getArrayFieldName()))
|
||||||
|
.findFirst();
|
||||||
|
if (col.isPresent()) {
|
||||||
|
Column column = col.get();
|
||||||
|
if (descriptionTasks.contains(taskType)) {
|
||||||
|
column.setDescription(newValue);
|
||||||
|
} else if (tagTasks.contains(taskType)) {
|
||||||
|
List<TagLabel> tags = JsonUtils.readObjects(newValue, TagLabel.class);
|
||||||
|
column.setTags(tags);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"The Column with name '%s' is not found in the dashboard data model.",
|
||||||
|
entityLink.getArrayFieldName()));
|
||||||
|
}
|
||||||
|
} else if (descriptionTasks.contains(taskType) && entityLink.getFieldName().equals(FIELD_DESCRIPTION)) {
|
||||||
|
dashboardDataModel.setDescription(newValue);
|
||||||
|
} else if (tagTasks.contains(taskType) && entityLink.getFieldName().equals("tags")) {
|
||||||
|
List<TagLabel> tags = JsonUtils.readObjects(newValue, TagLabel.class);
|
||||||
|
dashboardDataModel.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(dashboardDataModel);
|
||||||
|
patch = JsonUtils.getJsonPatch(oldJson, updatedEntityJson);
|
||||||
|
repository.patch(uriInfo, dashboardDataModel.getId(), user, patch);
|
||||||
|
break;
|
||||||
case PIPELINE:
|
case PIPELINE:
|
||||||
Pipeline pipeline = JsonUtils.readValue(json, Pipeline.class);
|
Pipeline pipeline = JsonUtils.readValue(json, Pipeline.class);
|
||||||
oldJson = JsonUtils.pojoToJson(pipeline);
|
oldJson = JsonUtils.pojoToJson(pipeline);
|
||||||
|
@ -549,20 +549,6 @@
|
|||||||
"EditDescription"
|
"EditDescription"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "dataModel",
|
|
||||||
"operations": [
|
|
||||||
"Create",
|
|
||||||
"Delete",
|
|
||||||
"ViewAll",
|
|
||||||
"EditAll",
|
|
||||||
"EditDescription",
|
|
||||||
"EditDisplayName",
|
|
||||||
"EditTags",
|
|
||||||
"EditOwner",
|
|
||||||
"EditLineage"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "dashboardDataModel",
|
"name": "dashboardDataModel",
|
||||||
"operations": [
|
"operations": [
|
||||||
|
@ -33,6 +33,7 @@ ENTITY_TYPE
|
|||||||
| 'testDefinition'
|
| 'testDefinition'
|
||||||
| 'testSuite'
|
| 'testSuite'
|
||||||
| 'testCase'
|
| 'testCase'
|
||||||
|
| 'dashboardDataModel'
|
||||||
;
|
;
|
||||||
ENTITY_FIELD
|
ENTITY_FIELD
|
||||||
: 'columns'
|
: 'columns'
|
||||||
|
@ -51,6 +51,7 @@ export enum AssetsType {
|
|||||||
DASHBOARD = 'dashboard',
|
DASHBOARD = 'dashboard',
|
||||||
PIPELINE = 'pipeline',
|
PIPELINE = 'pipeline',
|
||||||
MLMODEL = 'mlmodel',
|
MLMODEL = 'mlmodel',
|
||||||
|
DASHBOARD_DATA_MODEL = 'dashboardDataModel',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ChangeType {
|
export enum ChangeType {
|
||||||
|
@ -298,6 +298,7 @@
|
|||||||
"feature-plural-used": "Features Used",
|
"feature-plural-used": "Features Used",
|
||||||
"february": "February",
|
"february": "February",
|
||||||
"feed-lowercase": "feed",
|
"feed-lowercase": "feed",
|
||||||
|
"feed-plural": "Feeds",
|
||||||
"field-change": "Field Change",
|
"field-change": "Field Change",
|
||||||
"field-invalid": "{{field}} is invalid",
|
"field-invalid": "{{field}} is invalid",
|
||||||
"field-plural": "Fields",
|
"field-plural": "Fields",
|
||||||
|
@ -298,6 +298,7 @@
|
|||||||
"feature-plural-used": "Funcionalidades utilizadas",
|
"feature-plural-used": "Funcionalidades utilizadas",
|
||||||
"february": "Febrero",
|
"february": "Febrero",
|
||||||
"feed-lowercase": "feed",
|
"feed-lowercase": "feed",
|
||||||
|
"feed-plural": "Feeds",
|
||||||
"field-change": "Cambio de Campo",
|
"field-change": "Cambio de Campo",
|
||||||
"field-invalid": "{{field}} es inválido",
|
"field-invalid": "{{field}} es inválido",
|
||||||
"field-plural": "Campos",
|
"field-plural": "Campos",
|
||||||
|
@ -298,6 +298,7 @@
|
|||||||
"feature-plural-used": "Features Used",
|
"feature-plural-used": "Features Used",
|
||||||
"february": "February",
|
"february": "February",
|
||||||
"feed-lowercase": "feed",
|
"feed-lowercase": "feed",
|
||||||
|
"feed-plural": "Feeds",
|
||||||
"field-change": "Field Change",
|
"field-change": "Field Change",
|
||||||
"field-invalid": "{{field}} est imvalide",
|
"field-invalid": "{{field}} est imvalide",
|
||||||
"field-plural": "Champs",
|
"field-plural": "Champs",
|
||||||
|
@ -298,6 +298,7 @@
|
|||||||
"feature-plural-used": "使用される機能",
|
"feature-plural-used": "使用される機能",
|
||||||
"february": "2月",
|
"february": "2月",
|
||||||
"feed-lowercase": "フィード",
|
"feed-lowercase": "フィード",
|
||||||
|
"feed-plural": "Feeds",
|
||||||
"field-change": "フィールドを変更",
|
"field-change": "フィールドを変更",
|
||||||
"field-invalid": "{{field}}は不正です",
|
"field-invalid": "{{field}}は不正です",
|
||||||
"field-plural": "フィールド",
|
"field-plural": "フィールド",
|
||||||
|
@ -298,6 +298,7 @@
|
|||||||
"feature-plural-used": "Funções usadas",
|
"feature-plural-used": "Funções usadas",
|
||||||
"february": "Fevereiro",
|
"february": "Fevereiro",
|
||||||
"feed-lowercase": "feed",
|
"feed-lowercase": "feed",
|
||||||
|
"feed-plural": "Feeds",
|
||||||
"field-change": "Mudança de campo",
|
"field-change": "Mudança de campo",
|
||||||
"field-invalid": "{{field}} inválido",
|
"field-invalid": "{{field}} inválido",
|
||||||
"field-plural": "Campos",
|
"field-plural": "Campos",
|
||||||
|
@ -298,6 +298,7 @@
|
|||||||
"feature-plural-used": "Features Used",
|
"feature-plural-used": "Features Used",
|
||||||
"february": "February",
|
"february": "February",
|
||||||
"feed-lowercase": "feed",
|
"feed-lowercase": "feed",
|
||||||
|
"feed-plural": "Feeds",
|
||||||
"field-change": "域变动",
|
"field-change": "域变动",
|
||||||
"field-invalid": "{{field}} 无效",
|
"field-invalid": "{{field}} 无效",
|
||||||
"field-plural": "域",
|
"field-plural": "域",
|
||||||
|
@ -11,9 +11,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Card, Space, Tabs } from 'antd';
|
import { Card, Col, Row, Space, Tabs } from 'antd';
|
||||||
import AppState from 'AppState';
|
import AppState from 'AppState';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
|
import ActivityFeedList from 'components/ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||||
|
import ActivityThreadPanel from 'components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||||
import Description from 'components/common/description/Description';
|
import Description from 'components/common/description/Description';
|
||||||
import EntityPageInfo from 'components/common/entityPageInfo/EntityPageInfo';
|
import EntityPageInfo from 'components/common/entityPageInfo/EntityPageInfo';
|
||||||
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||||
@ -29,16 +31,22 @@ import {
|
|||||||
import SchemaEditor from 'components/schema-editor/SchemaEditor';
|
import SchemaEditor from 'components/schema-editor/SchemaEditor';
|
||||||
import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
|
import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
|
||||||
import { getServiceDetailsPath } from 'constants/constants';
|
import { getServiceDetailsPath } from 'constants/constants';
|
||||||
import { ENTITY_CARD_CLASS } from 'constants/entity.constants';
|
import { EntityField } from 'constants/Feeds.constants';
|
||||||
import { NO_PERMISSION_TO_VIEW } from 'constants/HelperTextUtil';
|
import { NO_PERMISSION_TO_VIEW } from 'constants/HelperTextUtil';
|
||||||
import { CSMode } from 'enums/codemirror.enum';
|
import { CSMode } from 'enums/codemirror.enum';
|
||||||
import { EntityInfo, EntityType } from 'enums/entity.enum';
|
import { EntityInfo, EntityType } from 'enums/entity.enum';
|
||||||
|
import { FeedFilter } from 'enums/mydata.enum';
|
||||||
import { ServiceCategory } from 'enums/service.enum';
|
import { ServiceCategory } from 'enums/service.enum';
|
||||||
import { OwnerType } from 'enums/user.enum';
|
import { OwnerType } from 'enums/user.enum';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare, Operation } from 'fast-json-patch';
|
||||||
|
import { CreateThread } from 'generated/api/feed/createThread';
|
||||||
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
|
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
|
||||||
|
import { Post, Thread, ThreadType } from 'generated/entity/feed/thread';
|
||||||
|
import { Paging } from 'generated/type/paging';
|
||||||
import { LabelType, State, TagSource } from 'generated/type/tagLabel';
|
import { LabelType, State, TagSource } from 'generated/type/tagLabel';
|
||||||
import { isUndefined, omitBy } from 'lodash';
|
import { EntityFieldThreadCount } from 'interface/feed.interface';
|
||||||
|
import jsonData from 'jsons/en';
|
||||||
|
import { isUndefined, omitBy, toString } from 'lodash';
|
||||||
import { EntityTags, ExtraInfo } from 'Models';
|
import { EntityTags, ExtraInfo } from 'Models';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -49,14 +57,22 @@ import {
|
|||||||
patchDataModelDetails,
|
patchDataModelDetails,
|
||||||
removeDataModelFollower,
|
removeDataModelFollower,
|
||||||
} from 'rest/dataModelsAPI';
|
} from 'rest/dataModelsAPI';
|
||||||
|
import { getAllFeeds, postFeedById, postThread } from 'rest/feedsAPI';
|
||||||
import {
|
import {
|
||||||
|
getCountBadge,
|
||||||
getCurrentUserId,
|
getCurrentUserId,
|
||||||
getEntityMissingError,
|
getEntityMissingError,
|
||||||
getEntityPlaceHolder,
|
getEntityPlaceHolder,
|
||||||
|
getFeedCounts,
|
||||||
getOwnerValue,
|
getOwnerValue,
|
||||||
} from 'utils/CommonUtils';
|
} from 'utils/CommonUtils';
|
||||||
import { getDataModelsDetailPath } from 'utils/DataModelsUtils';
|
import { getDataModelsDetailPath } from 'utils/DataModelsUtils';
|
||||||
import { getEntityName } from 'utils/EntityUtils';
|
import { getEntityFeedLink, getEntityName } from 'utils/EntityUtils';
|
||||||
|
import {
|
||||||
|
deletePost,
|
||||||
|
getEntityFieldThreadCounts,
|
||||||
|
updateThreadData,
|
||||||
|
} from 'utils/FeedUtils';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
|
||||||
import { serviceTypeLogo } from 'utils/ServiceUtils';
|
import { serviceTypeLogo } from 'utils/ServiceUtils';
|
||||||
import { getTagsWithoutTier, getTierTags } from 'utils/TableUtils';
|
import { getTagsWithoutTier, getTierTags } from 'utils/TableUtils';
|
||||||
@ -77,6 +93,21 @@ const DataModelsPage = () => {
|
|||||||
useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION);
|
useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION);
|
||||||
const [dataModelData, setDataModelData] = useState<DashboardDataModel>();
|
const [dataModelData, setDataModelData] = useState<DashboardDataModel>();
|
||||||
|
|
||||||
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
const [entityThread, setEntityThread] = useState<Thread[]>([]);
|
||||||
|
const [isEntityThreadLoading, setIsEntityThreadLoading] =
|
||||||
|
useState<boolean>(false);
|
||||||
|
const [paging, setPaging] = useState<Paging>({} as Paging);
|
||||||
|
|
||||||
|
const [feedCount, setFeedCount] = useState<number>(0);
|
||||||
|
const [entityFieldThreadCount, setEntityFieldThreadCount] = useState<
|
||||||
|
EntityFieldThreadCount[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const [entityFieldTaskCount, setEntityFieldTaskCount] = useState<
|
||||||
|
EntityFieldThreadCount[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
// get current user details
|
// get current user details
|
||||||
const currentUser = useMemo(
|
const currentUser = useMemo(
|
||||||
() => AppState.getCurrentUserDetails(),
|
() => AppState.getCurrentUserDetails(),
|
||||||
@ -159,6 +190,110 @@ const DataModelsPage = () => {
|
|||||||
];
|
];
|
||||||
}, [dataModelData, dashboardDataModelFQN, entityName]);
|
}, [dataModelData, dashboardDataModelFQN, entityName]);
|
||||||
|
|
||||||
|
const getFeedData = useCallback(
|
||||||
|
async (
|
||||||
|
after?: string,
|
||||||
|
feedFilter?: FeedFilter,
|
||||||
|
threadType?: ThreadType
|
||||||
|
) => {
|
||||||
|
setIsEntityThreadLoading(true);
|
||||||
|
!after && setEntityThread([]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data, paging: pagingObj } = await getAllFeeds(
|
||||||
|
getEntityFeedLink(
|
||||||
|
EntityType.DASHBOARD_DATA_MODEL,
|
||||||
|
dashboardDataModelFQN
|
||||||
|
),
|
||||||
|
after,
|
||||||
|
threadType,
|
||||||
|
feedFilter,
|
||||||
|
undefined,
|
||||||
|
currentUser?.id
|
||||||
|
);
|
||||||
|
setPaging(pagingObj);
|
||||||
|
setEntityThread((prevData) => [...prevData, ...data]);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorToast(
|
||||||
|
err as AxiosError,
|
||||||
|
t('server.entity-fetch-error', {
|
||||||
|
entity: t('label.feed-plural'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setIsEntityThreadLoading(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[dashboardDataModelFQN]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getEntityFeedCount = () => {
|
||||||
|
getFeedCounts(
|
||||||
|
EntityType.DASHBOARD_DATA_MODEL,
|
||||||
|
dashboardDataModelFQN,
|
||||||
|
setEntityFieldThreadCount,
|
||||||
|
setEntityFieldTaskCount,
|
||||||
|
setFeedCount
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deletePostHandler = (
|
||||||
|
threadId: string,
|
||||||
|
postId: string,
|
||||||
|
isThread: boolean
|
||||||
|
) => {
|
||||||
|
deletePost(threadId, postId, isThread, setEntityThread);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onThreadLinkSelect = (link: string) => {
|
||||||
|
setThreadLink(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
const postFeedHandler = (value: string, id: string) => {
|
||||||
|
const currentUser = AppState.userDetails?.name ?? AppState.users[0]?.name;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
message: value,
|
||||||
|
from: currentUser,
|
||||||
|
} as Post;
|
||||||
|
postFeedById(id, data)
|
||||||
|
.then((res) => {
|
||||||
|
if (res) {
|
||||||
|
const { id, posts } = res;
|
||||||
|
setEntityThread((pre) => {
|
||||||
|
return pre.map((thread) => {
|
||||||
|
if (thread.id === id) {
|
||||||
|
return { ...res, posts: posts?.slice(-3) };
|
||||||
|
} else {
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
getEntityFeedCount();
|
||||||
|
} else {
|
||||||
|
throw jsonData['api-error-messages']['unexpected-server-response'];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => {
|
||||||
|
showErrorToast(err, jsonData['api-error-messages']['add-feed-error']);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateThreadHandler = (
|
||||||
|
threadId: string,
|
||||||
|
postId: string,
|
||||||
|
isThread: boolean,
|
||||||
|
data: Operation[]
|
||||||
|
) => {
|
||||||
|
updateThreadData(threadId, postId, isThread, data, setEntityThread);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFeedFilterChange = useCallback(
|
||||||
|
(feedType, threadType) => {
|
||||||
|
getFeedData(undefined, feedType, threadType);
|
||||||
|
},
|
||||||
|
[paging]
|
||||||
|
);
|
||||||
const fetchResourcePermission = async (dashboardDataModelFQN: string) => {
|
const fetchResourcePermission = async (dashboardDataModelFQN: string) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
@ -178,6 +313,25 @@ const DataModelsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createThread = (data: CreateThread) => {
|
||||||
|
postThread(data)
|
||||||
|
.then((res) => {
|
||||||
|
if (res) {
|
||||||
|
setEntityThread((pre) => [...pre, res]);
|
||||||
|
getEntityFeedCount();
|
||||||
|
} else {
|
||||||
|
showErrorToast(
|
||||||
|
jsonData['api-error-messages']['unexpected-server-response']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => {
|
||||||
|
showErrorToast(
|
||||||
|
err,
|
||||||
|
jsonData['api-error-messages']['create-conversation-error']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
const fetchDataModelDetails = async (dashboardDataModelFQN: string) => {
|
const fetchDataModelDetails = async (dashboardDataModelFQN: string) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
@ -194,10 +348,8 @@ const DataModelsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateDataModelData = (updatedData: DashboardDataModel) => {
|
const onThreadPanelClose = () => {
|
||||||
const jsonPatch = compare(omitBy(dataModelData, isUndefined), updatedData);
|
setThreadLink('');
|
||||||
|
|
||||||
return patchDataModelDetails(dataModelData?.id ?? '', jsonPatch);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTabChange = (tabValue: string) => {
|
const handleTabChange = (tabValue: string) => {
|
||||||
@ -208,6 +360,12 @@ const DataModelsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleUpdateDataModelData = (updatedData: DashboardDataModel) => {
|
||||||
|
const jsonPatch = compare(omitBy(dataModelData, isUndefined), updatedData);
|
||||||
|
|
||||||
|
return patchDataModelDetails(dataModelData?.id ?? '', jsonPatch);
|
||||||
|
};
|
||||||
|
|
||||||
const handleUpdateDescription = async (updatedDescription: string) => {
|
const handleUpdateDescription = async (updatedDescription: string) => {
|
||||||
try {
|
try {
|
||||||
const { description: newDescription, version } =
|
const { description: newDescription, version } =
|
||||||
@ -301,6 +459,7 @@ const DataModelsPage = () => {
|
|||||||
tags: newTags,
|
tags: newTags,
|
||||||
version,
|
version,
|
||||||
}));
|
}));
|
||||||
|
getEntityFeedCount();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast(error as AxiosError);
|
showErrorToast(error as AxiosError);
|
||||||
}
|
}
|
||||||
@ -319,6 +478,7 @@ const DataModelsPage = () => {
|
|||||||
owner: newOwner,
|
owner: newOwner,
|
||||||
version,
|
version,
|
||||||
}));
|
}));
|
||||||
|
getEntityFeedCount();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast(error as AxiosError);
|
showErrorToast(error as AxiosError);
|
||||||
}
|
}
|
||||||
@ -347,6 +507,7 @@ const DataModelsPage = () => {
|
|||||||
tags: newTags,
|
tags: newTags,
|
||||||
version,
|
version,
|
||||||
}));
|
}));
|
||||||
|
getEntityFeedCount();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast(error as AxiosError);
|
showErrorToast(error as AxiosError);
|
||||||
@ -372,9 +533,16 @@ const DataModelsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (tab === DATA_MODELS_DETAILS_TABS.ACTIVITY) {
|
||||||
|
getFeedData();
|
||||||
|
}
|
||||||
|
}, [tab, dashboardDataModelFQN]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasViewPermission) {
|
if (hasViewPermission) {
|
||||||
fetchDataModelDetails(dashboardDataModelFQN);
|
fetchDataModelDetails(dashboardDataModelFQN);
|
||||||
|
getEntityFeedCount();
|
||||||
}
|
}
|
||||||
}, [dashboardDataModelFQN, dataModelPermissions]);
|
}, [dashboardDataModelFQN, dataModelPermissions]);
|
||||||
|
|
||||||
@ -406,6 +574,14 @@ const DataModelsPage = () => {
|
|||||||
canDelete={dataModelPermissions.Delete}
|
canDelete={dataModelPermissions.Delete}
|
||||||
currentOwner={owner}
|
currentOwner={owner}
|
||||||
deleted={deleted}
|
deleted={deleted}
|
||||||
|
entityFieldTasks={getEntityFieldThreadCounts(
|
||||||
|
EntityField.TAGS,
|
||||||
|
entityFieldTaskCount
|
||||||
|
)}
|
||||||
|
entityFieldThreads={getEntityFieldThreadCounts(
|
||||||
|
EntityField.TAGS,
|
||||||
|
entityFieldThreadCount
|
||||||
|
)}
|
||||||
entityFqn={dashboardDataModelFQN}
|
entityFqn={dashboardDataModelFQN}
|
||||||
entityId={entityId}
|
entityId={entityId}
|
||||||
entityName={entityName || ''}
|
entityName={entityName || ''}
|
||||||
@ -423,7 +599,8 @@ const DataModelsPage = () => {
|
|||||||
titleLinks={breadcrumbTitles}
|
titleLinks={breadcrumbTitles}
|
||||||
updateOwner={hasEditOwnerPermission ? handleUpdateOwner : undefined}
|
updateOwner={hasEditOwnerPermission ? handleUpdateOwner : undefined}
|
||||||
updateTier={hasEditTierPermission ? handleUpdateTier : undefined}
|
updateTier={hasEditTierPermission ? handleUpdateTier : undefined}
|
||||||
version={version + ''}
|
version={toString(version)}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
<Tabs activeKey={tab} className="h-full" onChange={handleTabChange}>
|
<Tabs activeKey={tab} className="h-full" onChange={handleTabChange}>
|
||||||
<Tabs.TabPane
|
<Tabs.TabPane
|
||||||
@ -433,7 +610,7 @@ const DataModelsPage = () => {
|
|||||||
{t('label.model')}
|
{t('label.model')}
|
||||||
</span>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Card className={ENTITY_CARD_CLASS}>
|
<Card className="h-full">
|
||||||
<Space className="w-full" direction="vertical" size={8}>
|
<Space className="w-full" direction="vertical" size={8}>
|
||||||
<Description
|
<Description
|
||||||
description={description}
|
description={description}
|
||||||
@ -460,6 +637,38 @@ const DataModelsPage = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
|
|
||||||
|
<Tabs.TabPane
|
||||||
|
key={DATA_MODELS_DETAILS_TABS.ACTIVITY}
|
||||||
|
tab={
|
||||||
|
<span data-testid={DATA_MODELS_DETAILS_TABS.ACTIVITY}>
|
||||||
|
{t('label.activity-feed-and-task-plural')}{' '}
|
||||||
|
{getCountBadge(
|
||||||
|
feedCount,
|
||||||
|
'',
|
||||||
|
DATA_MODELS_DETAILS_TABS.ACTIVITY === tab
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
}>
|
||||||
|
<Card className="m-y-md">
|
||||||
|
<Row justify="center">
|
||||||
|
<Col span={18}>
|
||||||
|
<div id="activityfeed">
|
||||||
|
<ActivityFeedList
|
||||||
|
isEntityFeed
|
||||||
|
withSidePanel
|
||||||
|
deletePostHandler={deletePostHandler}
|
||||||
|
entityName={entityName}
|
||||||
|
feedList={entityThread}
|
||||||
|
isFeedLoading={isEntityThreadLoading}
|
||||||
|
postFeedHandler={postFeedHandler}
|
||||||
|
updateThreadHandler={updateThreadHandler}
|
||||||
|
onFeedFiltersUpdate={handleFeedFilterChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
</Tabs.TabPane>
|
||||||
{dataModelData?.sql && (
|
{dataModelData?.sql && (
|
||||||
<Tabs.TabPane
|
<Tabs.TabPane
|
||||||
key={DATA_MODELS_DETAILS_TABS.SQL}
|
key={DATA_MODELS_DETAILS_TABS.SQL}
|
||||||
@ -468,7 +677,7 @@ const DataModelsPage = () => {
|
|||||||
{t('label.sql-uppercase')}
|
{t('label.sql-uppercase')}
|
||||||
</span>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Card className={ENTITY_CARD_CLASS}>
|
<Card className="h-full">
|
||||||
<SchemaEditor
|
<SchemaEditor
|
||||||
editorClass="custom-code-mirror-theme full-screen-editor-height"
|
editorClass="custom-code-mirror-theme full-screen-editor-height"
|
||||||
mode={{ name: CSMode.SQL }}
|
mode={{ name: CSMode.SQL }}
|
||||||
@ -500,6 +709,18 @@ const DataModelsPage = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
|
{threadLink ? (
|
||||||
|
<ActivityThreadPanel
|
||||||
|
createThread={createThread}
|
||||||
|
deletePostHandler={deletePostHandler}
|
||||||
|
open={Boolean(threadLink)}
|
||||||
|
postFeedHandler={postFeedHandler}
|
||||||
|
threadLink={threadLink}
|
||||||
|
updateThreadHandler={updateThreadHandler}
|
||||||
|
onCancel={onThreadPanelClose}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</PageContainerV1>
|
</PageContainerV1>
|
||||||
);
|
);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
|
||||||
import { DatabaseSchema } from 'generated/entity/data/databaseSchema';
|
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';
|
||||||
@ -24,7 +25,8 @@ export type EntityData =
|
|||||||
| Dashboard
|
| Dashboard
|
||||||
| Pipeline
|
| Pipeline
|
||||||
| Mlmodel
|
| Mlmodel
|
||||||
| DatabaseSchema;
|
| DatabaseSchema
|
||||||
|
| DashboardDataModel;
|
||||||
|
|
||||||
export interface Option {
|
export interface Option {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -14,6 +14,7 @@ import { AxiosResponse } from 'axios';
|
|||||||
import { Operation } from 'fast-json-patch';
|
import { Operation } from 'fast-json-patch';
|
||||||
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
|
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
|
||||||
import { EntityReference } from 'generated/type/entityReference';
|
import { EntityReference } from 'generated/type/entityReference';
|
||||||
|
import { getURLWithQueryFields } from 'utils/APIUtils';
|
||||||
import APIClient from './index';
|
import APIClient from './index';
|
||||||
|
|
||||||
const URL = '/dashboard/datamodels';
|
const URL = '/dashboard/datamodels';
|
||||||
@ -37,6 +38,20 @@ export const getDataModelsByName = async (
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDataModelDetailsByFQN = async (
|
||||||
|
databaseSchemaName: string,
|
||||||
|
arrQueryFields?: string | string[]
|
||||||
|
) => {
|
||||||
|
const url = `${getURLWithQueryFields(
|
||||||
|
`/dashboard/datamodels/name/${databaseSchemaName}`,
|
||||||
|
arrQueryFields
|
||||||
|
)}`;
|
||||||
|
|
||||||
|
const response = await APIClient.get<DashboardDataModel>(url);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
export const patchDataModelDetails = async (id: string, data: Operation[]) => {
|
export const patchDataModelDetails = async (id: string, data: Operation[]) => {
|
||||||
const response = await APIClient.patch<
|
const response = await APIClient.patch<
|
||||||
Operation[],
|
Operation[],
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
PLACEHOLDER_ROUTE_TAB,
|
PLACEHOLDER_ROUTE_TAB,
|
||||||
ROUTES,
|
ROUTES,
|
||||||
} from 'constants/constants';
|
} from 'constants/constants';
|
||||||
|
import { TabSpecificField } from 'enums/entity.enum';
|
||||||
import { Column } from 'generated/entity/data/dashboardDataModel';
|
import { Column } from 'generated/entity/data/dashboardDataModel';
|
||||||
import { LabelType, State, TagLabel } from 'generated/type/tagLabel';
|
import { LabelType, State, TagLabel } from 'generated/type/tagLabel';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
@ -112,3 +113,6 @@ export const updateDataModelColumnTags = (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const defaultFields = `${TabSpecificField.TAGS}, ${TabSpecificField.OWNER},
|
||||||
|
${TabSpecificField.FOLLOWERS}`;
|
||||||
|
@ -43,6 +43,7 @@ import {
|
|||||||
getDashboardDetailsPath,
|
getDashboardDetailsPath,
|
||||||
getDatabaseDetailsPath,
|
getDatabaseDetailsPath,
|
||||||
getDatabaseSchemaDetailsPath,
|
getDatabaseSchemaDetailsPath,
|
||||||
|
getDataModelDetailsPath,
|
||||||
getEditWebhookPath,
|
getEditWebhookPath,
|
||||||
getMlModelPath,
|
getMlModelPath,
|
||||||
getPipelineDetailsPath,
|
getPipelineDetailsPath,
|
||||||
@ -260,6 +261,9 @@ export const getEntityLink = (
|
|||||||
case SearchIndex.TAG:
|
case SearchIndex.TAG:
|
||||||
return getTagsDetailsPath(fullyQualifiedName);
|
return getTagsDetailsPath(fullyQualifiedName);
|
||||||
|
|
||||||
|
case EntityType.DASHBOARD_DATA_MODEL:
|
||||||
|
return getDataModelDetailsPath(fullyQualifiedName);
|
||||||
|
|
||||||
case SearchIndex.TABLE:
|
case SearchIndex.TABLE:
|
||||||
case EntityType.TABLE:
|
case EntityType.TABLE:
|
||||||
default:
|
default:
|
||||||
|
@ -23,6 +23,7 @@ import {
|
|||||||
} 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 { getDatabaseSchemaDetailsByFQN } from 'rest/databaseAPI';
|
||||||
|
import { getDataModelDetailsByFQN } from 'rest/dataModelsAPI';
|
||||||
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';
|
||||||
@ -44,6 +45,7 @@ import { TaskType } from '../generated/entity/feed/thread';
|
|||||||
import { getPartialNameFromTableFQN } from './CommonUtils';
|
import { getPartialNameFromTableFQN } from './CommonUtils';
|
||||||
import { defaultFields as DashboardFields } from './DashboardDetailsUtils';
|
import { defaultFields as DashboardFields } from './DashboardDetailsUtils';
|
||||||
import { defaultFields as DatabaseSchemaFields } from './DatabaseSchemaDetailsUtils';
|
import { defaultFields as DatabaseSchemaFields } from './DatabaseSchemaDetailsUtils';
|
||||||
|
import { defaultFields as DataModelFields } from './DataModelsUtils';
|
||||||
import { defaultFields as TableFields } from './DatasetDetailsUtils';
|
import { defaultFields as TableFields } from './DatasetDetailsUtils';
|
||||||
import { getEntityName } from './EntityUtils';
|
import { getEntityName } from './EntityUtils';
|
||||||
import { defaultFields as MlModelFields } from './MlModelDetailsUtils';
|
import { defaultFields as MlModelFields } from './MlModelDetailsUtils';
|
||||||
@ -189,6 +191,7 @@ export const TASK_ENTITIES = [
|
|||||||
EntityType.PIPELINE,
|
EntityType.PIPELINE,
|
||||||
EntityType.MLMODEL,
|
EntityType.MLMODEL,
|
||||||
EntityType.DATABASE_SCHEMA,
|
EntityType.DATABASE_SCHEMA,
|
||||||
|
EntityType.DASHBOARD_DATA_MODEL,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getBreadCrumbList = (
|
export const getBreadCrumbList = (
|
||||||
@ -327,6 +330,15 @@ export const fetchEntityDetail = (
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EntityType.DASHBOARD_DATA_MODEL:
|
||||||
|
getDataModelDetailsByFQN(entityFQN, DataModelFields)
|
||||||
|
.then((res) => {
|
||||||
|
setEntityData(res);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => showErrorToast(err));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user