ui: aligned assets tab ui of teams page with glossary term page (#13291)

* ui: aligned assets tab ui of teams page with glossary term page

* move index's to constant file

* fixed no data placeholder flickering issue

* updated default layout option
This commit is contained in:
Shailesh Parmar 2023-09-25 10:27:50 +05:30 committed by GitHub
parent 65f65137e6
commit 621afae8d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 155 additions and 193 deletions

View File

@ -11,7 +11,7 @@
* limitations under the License.
*/
import { Button, Menu, Space } from 'antd';
import { Button, Col, Menu, Row, Skeleton, Space } from 'antd';
import type { ButtonType } from 'antd/lib/button';
import classNames from 'classnames';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
@ -19,12 +19,14 @@ import NextPrevious from 'components/common/next-previous/NextPrevious';
import { PagingHandlerParams } from 'components/common/next-previous/NextPrevious.interface';
import PageLayoutV1 from 'components/containers/PageLayoutV1';
import ExploreSearchCard from 'components/ExploreV1/ExploreSearchCard/ExploreSearchCard';
import Loader from 'components/Loader/Loader';
import {
SearchedDataProps,
SourceType,
} from 'components/searched-data/SearchedData.interface';
import { AssetsFilterOptions } from 'constants/Assets.constants';
import {
AssetsFilterOptions,
ASSETS_INDEXES,
} from 'constants/Assets.constants';
import { PAGE_SIZE } from 'constants/constants';
import { GLOSSARIES_DOCS } from 'constants/docs.constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
@ -117,22 +119,15 @@ const AssetsTabs = forwardRef(
return `(domain.fullyQualifiedName:"${fqn}")`;
} else if (type === AssetsOfEntity.DATA_PRODUCT) {
return `(dataProducts.fullyQualifiedName:"${fqn}")`;
} else if (type === AssetsOfEntity.TEAM) {
return `(owner.fullyQualifiedName:"${fqn}")`;
} else {
return `(tags.tagFQN:"${glossaryName}")`;
}
}, [type, glossaryName, fqn]);
const searchIndexes = useMemo(() => {
const indexesToFetch = [
SearchIndex.TABLE,
SearchIndex.TOPIC,
SearchIndex.DASHBOARD,
SearchIndex.PIPELINE,
SearchIndex.MLMODEL,
SearchIndex.CONTAINER,
SearchIndex.STORED_PROCEDURE,
SearchIndex.DASHBOARD_DATA_MODEL,
];
const indexesToFetch = [...ASSETS_INDEXES];
if (type !== AssetsOfEntity.GLOSSARY) {
indexesToFetch.push(SearchIndex.GLOSSARY);
}
@ -159,8 +154,8 @@ const AssetsTabs = forwardRef(
glossaryResponse,
]) => {
const counts = {
[EntityType.TOPIC]: topicResponse.data.hits.total.value,
[EntityType.TABLE]: tableResponse.data.hits.total.value,
[EntityType.TOPIC]: topicResponse.data.hits.total.value,
[EntityType.DASHBOARD]: dashboardResponse.data.hits.total.value,
[EntityType.PIPELINE]: pipelineResponse.data.hits.total.value,
[EntityType.MLMODEL]: mlmodelResponse.data.hits.total.value,
@ -214,6 +209,7 @@ const AssetsTabs = forwardRef(
page?: number;
}) => {
try {
setIsLoading(true);
const res = await searchData(
'',
page,
@ -246,53 +242,66 @@ const AssetsTabs = forwardRef(
hits[0] && setSelectedCard(hits[0]._source as SourceType);
} catch (_) {
// Nothing here
} finally {
setIsLoading(false);
}
},
[activeFilter, currentPage]
);
const assetListing = useMemo(
() =>
data.length ? (
<div className="assets-data-container">
{data.map(({ _source, _id = '' }, index) => (
<ExploreSearchCard
className={classNames(
'm-b-sm cursor-pointer',
selectedCard?.id === _source.id ? 'highlight-card' : ''
)}
handleSummaryPanelDisplay={setSelectedCard}
id={_id}
key={index}
showTags={false}
source={_source}
/>
))}
{total > PAGE_SIZE && data.length > 0 && (
<NextPrevious
isNumberBased
currentPage={currentPage}
pageSize={PAGE_SIZE}
paging={{ total }}
pagingHandler={({ currentPage }: PagingHandlerParams) =>
setCurrentPage(currentPage)
}
/>
)}
</div>
) : (
<div className="m-t-xlg">
<ErrorPlaceHolder
doc={GLOSSARIES_DOCS}
heading={t('label.asset')}
permission={permissions.Create}
type={ERROR_PLACEHOLDER_TYPE.CREATE}
onClick={onAddAsset}
const assetListing = useMemo(() => {
if (isLoading) {
return (
<Row gutter={[0, 16]}>
<Col span={24}>
<Skeleton />
</Col>
<Col span={24}>
<Skeleton />
</Col>
</Row>
);
}
return data.length ? (
<div className="assets-data-container">
{data.map(({ _source, _id = '' }, index) => (
<ExploreSearchCard
className={classNames(
'm-b-sm cursor-pointer',
selectedCard?.id === _source.id ? 'highlight-card' : ''
)}
handleSummaryPanelDisplay={setSelectedCard}
id={_id}
key={index}
showTags={false}
source={_source}
/>
</div>
),
[data, total, currentPage, selectedCard, setSelectedCard]
);
))}
{total > PAGE_SIZE && data.length > 0 && (
<NextPrevious
isNumberBased
currentPage={currentPage}
pageSize={PAGE_SIZE}
paging={{ total }}
pagingHandler={({ currentPage }: PagingHandlerParams) =>
setCurrentPage(currentPage)
}
/>
)}
</div>
) : (
<div className="m-t-xlg">
<ErrorPlaceHolder
doc={GLOSSARIES_DOCS}
heading={t('label.asset')}
permission={permissions.Create}
type={ERROR_PLACEHOLDER_TYPE.CREATE}
onClick={onAddAsset}
/>
</div>
);
}, [data, isLoading, total, currentPage, selectedCard, setSelectedCard]);
const assetsHeader = useMemo(() => {
if (viewType === AssetsViewType.PILLS) {
@ -385,10 +394,6 @@ const AssetsTabs = forwardRef(
}
}, [isSummaryPanelOpen]);
if (isLoading) {
return <Loader />;
}
return (
<div
className={classNames(

View File

@ -18,6 +18,7 @@ export enum AssetsOfEntity {
GLOSSARY = 'GLOSSARY',
DOMAIN = 'DOMAIN',
DATA_PRODUCT = 'DATA_PRODUCT',
TEAM = 'TEAM',
}
export enum AssetsViewType {

View File

@ -44,9 +44,13 @@ import { AxiosError } from 'axios';
import classNames from 'classnames';
import { ManageButtonItemLabel } from 'components/common/ManageButtonContentItem/ManageButtonContentItem.component';
import { OwnerLabel } from 'components/common/OwnerLabel/OwnerLabel.component';
import TableDataCardV2 from 'components/common/table-data-card-v2/TableDataCardV2';
import TeamTypeSelect from 'components/common/TeamTypeSelect/TeamTypeSelect.component';
import { useEntityExportModalProvider } from 'components/Entity/EntityExportModalProvider/EntityExportModalProvider.component';
import EntitySummaryPanel from 'components/Explore/EntitySummaryPanel/EntitySummaryPanel.component';
import { EntityDetailsObjectInterface } from 'components/Explore/explore.interface';
import AssetsTabs from 'components/Glossary/GlossaryTerms/tabs/AssetsTabs.component';
import { AssetsOfEntity } from 'components/Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
import { ROUTES } from 'constants/constants';
import {
GlobalSettingOptions,
GlobalSettingsMenuCategory,
@ -67,19 +71,12 @@ import {
import AddAttributeModal from 'pages/RolesPage/AddAttributeModal/AddAttributeModal';
import { ImportType } from 'pages/teams/ImportTeamsPage/ImportTeamsPage.interface';
import Qs from 'qs';
import React, {
Fragment,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory, useLocation } from 'react-router-dom';
import { getSuggestions } from 'rest/miscAPI';
import { exportTeam, restoreTeam } from 'rest/teamsAPI';
import AppState from '../../../AppState';
import { LIST_SIZE, ROUTES } from '../../../constants/constants';
import { ROLE_DOCS, TEAMS_DOCS } from '../../../constants/docs.constants';
import { EntityAction, EntityType } from '../../../enums/entity.enum';
import { OwnerType } from '../../../enums/user.enum';
@ -90,14 +87,13 @@ import {
User,
} from '../../../generated/entity/teams/user';
import { EntityReference } from '../../../generated/type/entityReference';
import { Paging } from '../../../generated/type/paging';
import {
AddAttribute,
PlaceholderProps,
TeamDetailsProp,
} from '../../../interface/teamsAndUsers.interface';
import { getCountBadge, hasEditAccess } from '../../../utils/CommonUtils';
import { filterEntityAssets, getEntityName } from '../../../utils/EntityUtils';
import { getEntityName } from '../../../utils/EntityUtils';
import { checkPermission } from '../../../utils/PermissionsUtils';
import {
getSettingsPathWithFqn,
@ -111,7 +107,6 @@ import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
import Description from '../../common/description/Description';
import ManageButton from '../../common/entityPageInfo/ManageButton/ManageButton';
import ErrorPlaceHolder from '../../common/error-with-placeholder/ErrorPlaceHolder';
import NextPrevious from '../../common/next-previous/NextPrevious';
import Searchbar from '../../common/searchbar/Searchbar';
import TitleBreadcrumb from '../../common/title-breadcrumb/title-breadcrumb.component';
import { TitleBreadcrumbProps } from '../../common/title-breadcrumb/title-breadcrumb.interface';
@ -127,7 +122,7 @@ import './teams.less';
import { UserTab } from './UserTab/UserTab.component';
const TeamDetailsV1 = ({
assets,
assetsCount,
hasAccess,
currentTeam,
currentTeamUsers,
@ -152,7 +147,6 @@ const TeamDetailsV1 = ({
handleAddUser,
removeUserFromTeam,
afterDeleteAction,
onAssetsPaginate,
parentTeams,
entityPermissions,
isFetchingAdvancedDetails,
@ -207,6 +201,8 @@ const TeamDetailsV1 = ({
}>();
const [isModalLoading, setIsModalLoading] = useState<boolean>(false);
const [isEmailEdit, setIsEmailEdit] = useState<boolean>(false);
const [previewAsset, setPreviewAsset] =
useState<EntityDetailsObjectInterface>();
const [showTypeSelector, setShowTypeSelector] = useState(false);
const { showModal } = useEntityExportModalProvider();
@ -236,7 +232,8 @@ const TeamDetailsV1 = ({
currentTeam,
isGroupType,
isOrganization,
teamCount
teamCount,
assetsCount
).map((tab) => ({
...tab,
label: (
@ -252,7 +249,14 @@ const TeamDetailsV1 = ({
}));
return allTabs;
}, [currentTeam, teamUserPaging, searchTerm, teamCount, currentTab]);
}, [
currentTeam,
teamUserPaging,
searchTerm,
teamCount,
currentTab,
assetsCount,
]);
const createTeamPermission = useMemo(
() =>
@ -705,55 +709,6 @@ const TeamDetailsV1 = ({
]
);
/**
* Check for current team datasets and return the dataset cards
* @returns - dataset cards
*/
const getAssetDetailCards = () => {
const ownData = filterEntityAssets(currentTeam?.owns || []);
if (isEmpty(ownData)) {
return fetchErrorPlaceHolder({
type: ERROR_PLACEHOLDER_TYPE.ASSIGN,
heading: t('label.asset'),
permission: entityPermissions.EditAll,
button: (
<Button
ghost
className="p-x-lg"
data-testid="add-placeholder-button"
icon={<PlusOutlined />}
type="primary"
onClick={() => history.push(ROUTES.EXPLORE)}>
{t('label.add')}
</Button>
),
});
}
return (
<div data-testid="table-container">
{assets.data.map(({ _source, _id = '' }, index) => (
<TableDataCardV2
className="m-b-sm cursor-pointer"
id={_id}
key={index}
source={_source}
/>
))}
{assets.total > LIST_SIZE && assets.data.length > 0 && (
<NextPrevious
isNumberBased
currentPage={assets.currPage}
pageSize={LIST_SIZE}
paging={{} as Paging}
pagingHandler={onAssetsPaginate}
/>
)}
</div>
);
};
const teamActionButton = (alreadyJoined: boolean, isJoinable: boolean) => {
return alreadyJoined ? (
isJoinable || hasAccess ? (
@ -989,16 +944,16 @@ const TeamDetailsV1 = ({
}
return (
<div
className="h-full d-flex flex-col flex-grow"
data-testid="team-details-container">
<Row className="h-full flex-grow" data-testid="team-details-container">
{!isEmpty(currentTeam) ? (
<Fragment>
<Col span={previewAsset ? 18 : 24}>
{!isOrganization && (
<TitleBreadcrumb className="p-b-xs" titleLinks={slashedTeamName} />
)}
<div
className="d-flex justify-between items-center"
className={classNames('d-flex justify-between items-center', {
'm-r-xs': previewAsset,
})}
data-testid="header">
{getTeamHeading()}
{!isOrganization ? (
@ -1153,7 +1108,15 @@ const TeamDetailsV1 = ({
/>
)}
{currentTab === TeamsPageTab.ASSETS && getAssetDetailCards()}
{currentTab === TeamsPageTab.ASSETS && (
<AssetsTabs
isSummaryPanelOpen
permissions={entityPermissions}
type={AssetsOfEntity.TEAM}
onAddAsset={() => history.push(ROUTES.EXPLORE)}
onAssetClick={setPreviewAsset}
/>
)}
{currentTab === TeamsPageTab.ROLES &&
(isEmpty(currentTeam.defaultRoles || []) ? (
@ -1274,7 +1237,7 @@ const TeamDetailsV1 = ({
</div>
)}
</div>
</Fragment>
</Col>
) : (
fetchErrorPlaceHolder({
onClick: () => handleAddTeam(true),
@ -1284,6 +1247,15 @@ const TeamDetailsV1 = ({
})
)}
{previewAsset && (
<Col className="border-left team-assets-right-panel" span={6}>
<EntitySummaryPanel
entityDetails={previewAsset}
handleClosePanel={() => setPreviewAsset(undefined)}
/>
</Col>
)}
<ConfirmationModal
bodyText={removeUserBodyText(deletingUser.leave)}
cancelText={t('label.cancel')}
@ -1334,7 +1306,7 @@ const TeamDetailsV1 = ({
</Typography.Text>
</Modal>
)}
</div>
</Row>
);
};

View File

@ -13,14 +13,14 @@
import { t } from 'i18next';
import { Team } from '../../../generated/entity/teams/team';
import { filterEntityAssets } from '../../../utils/EntityUtils';
import { TeamsPageTab } from './team.interface';
export const getTabs = (
currentTeam: Team,
isGroupType: boolean,
isOrganization: boolean,
teamsCount: number
teamsCount: number,
assetsCount: number
) => {
const tabs = {
teams: {
@ -35,7 +35,7 @@ export const getTabs = (
},
assets: {
name: t('label.asset-plural'),
count: filterEntityAssets(currentTeam?.owns || []).length,
count: assetsCount,
key: TeamsPageTab.ASSETS,
},
roles: {

View File

@ -75,3 +75,12 @@
}
}
}
.team-assets-right-panel {
margin-top: -24px;
margin-bottom: -24px;
.summary-panel-container {
height: 100%;
border: 0;
}
}

View File

@ -66,3 +66,14 @@ export const AssetsFilterOptions: Array<{
value: SearchIndex.DASHBOARD_DATA_MODEL,
},
];
export const ASSETS_INDEXES = [
SearchIndex.TABLE,
SearchIndex.TOPIC,
SearchIndex.DASHBOARD,
SearchIndex.PIPELINE,
SearchIndex.MLMODEL,
SearchIndex.CONTAINER,
SearchIndex.STORED_PROCEDURE,
SearchIndex.DASHBOARD_DATA_MODEL,
];

View File

@ -15,7 +15,7 @@ import { NextPreviousProps } from 'components/common/next-previous/NextPrevious.
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { Operation } from 'fast-json-patch';
import { AssetsDataType, FormErrorData } from 'Models';
import { FormErrorData } from 'Models';
import { EntityType } from '../enums/entity.enum';
import { UserType } from '../enums/user.enum';
import { Team } from '../generated/entity/teams/team';
@ -93,9 +93,9 @@ export interface TeamsAndUsersProps {
}
export interface TeamDetailsProp {
assetsCount: number;
currentTeam: Team;
teams?: Team[];
assets: AssetsDataType;
currentTeamUsers: User[];
teamUserPaging: Paging;
currentTeamUserPage: number;
@ -120,7 +120,6 @@ export interface TeamDetailsProp {
handleLeaveTeamClick: (id: string, data: Operation[]) => Promise<void>;
childTeams: Team[];
showDeletedTeam: boolean;
onAssetsPaginate: NextPreviousProps['pagingHandler'];
onShowDeletedTeamChange: () => void;
parentTeams: Team[];
onTeamExpand: (

View File

@ -23,11 +23,11 @@ import {
} from 'components/PermissionProvider/PermissionProvider.interface';
import { TeamsPageTab } from 'components/Team/TeamDetails/team.interface';
import TeamDetailsV1 from 'components/Team/TeamDetails/TeamDetailsV1';
import { ASSETS_INDEXES } from 'constants/Assets.constants';
import { HTTP_STATUS_CODE } from 'constants/auth.constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { compare, Operation } from 'fast-json-patch';
import { cloneDeep, isEmpty, isUndefined } from 'lodash';
import { AssetsDataType } from 'Models';
import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory, useParams } from 'react-router-dom';
@ -43,11 +43,9 @@ import { getEncodedFqn } from 'utils/StringsUtils';
import AppState from '../../AppState';
import {
INITIAL_PAGING_VALUE,
LIST_SIZE,
PAGE_SIZE_BASE,
pagingObject,
} from '../../constants/constants';
import { myDataSearchIndex } from '../../constants/Mydata.constants';
import { SearchIndex } from '../../enums/search.enum';
import { CreateTeam, TeamType } from '../../generated/api/teams/createTeam';
import { EntityReference } from '../../generated/entity/data/table';
@ -56,7 +54,7 @@ import { User } from '../../generated/entity/teams/user';
import { Paging } from '../../generated/type/paging';
import { useAuth } from '../../hooks/authHooks';
import { SearchResponse } from '../../interface/search.interface';
import { formatUsersResponse, SearchEntityHits } from '../../utils/APIUtils';
import { formatUsersResponse } from '../../utils/APIUtils';
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
import { getSettingPath, getTeamsWithFqnPath } from '../../utils/RouterUtils';
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
@ -83,11 +81,7 @@ const TeamsPage = () => {
const [userSearchValue, setUserSearchValue] = useState<string>('');
const [isAddingTeam, setIsAddingTeam] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [assets, setAssets] = useState<AssetsDataType>({
data: [],
total: 0,
currPage: 1,
});
const [assets, setAssets] = useState<number>(0);
const [parentTeams, setParentTeams] = useState<Team[]>([]);
const [entityPermissions, setEntityPermissions] =
@ -268,43 +262,23 @@ const TeamsPage = () => {
}
};
const fetchAssets = () => {
const fetchAssets = async () => {
if (selectedTeam.id && isGroupType) {
searchData(
``,
assets.currPage,
LIST_SIZE,
`owner.id:${selectedTeam.id}`,
'',
'',
myDataSearchIndex
)
.then((res) => {
const hits = res?.data?.hits?.hits as SearchEntityHits;
if (hits?.length > 0) {
const total = res.data.hits.total.value;
setAssets({
data: hits,
total,
currPage: assets.currPage,
});
} else {
const total = 0;
setAssets({
data: [],
total,
currPage: assets.currPage,
});
}
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-error', {
entity: t('label.team-asset-plural'),
})
);
});
try {
const res = await searchData(
``,
0,
0,
`owner.id:${selectedTeam.id}`,
'',
'',
ASSETS_INDEXES
);
const total = res?.data?.hits?.total.value ?? 0;
setAssets(total);
} catch (error) {
// Error
}
}
};
@ -584,14 +558,6 @@ const TeamsPage = () => {
setShowDeletedTeam((pre) => !pre);
};
const handleAssetsPaginate = ({ currentPage }: PagingHandlerParams) => {
setAssets((pre) => ({ ...pre, currPage: currentPage }));
};
useEffect(() => {
fetchAssets();
}, [assets.currPage]);
useEffect(() => {
if (hasViewPermission && currentFqn !== fqn) {
if (fqn) {
@ -642,7 +608,7 @@ const TeamsPage = () => {
<>
<TeamDetailsV1
afterDeleteAction={afterDeleteAction}
assets={assets}
assetsCount={assets}
childTeams={allTeam}
currentTeam={selectedTeam}
currentTeamUserPage={currentUserPage}
@ -667,7 +633,6 @@ const TeamsPage = () => {
teamUserPagingHandler={userPagingHandler}
teamUsersSearchText={userSearchValue}
updateTeamHandler={updateTeamHandler}
onAssetsPaginate={handleAssetsPaginate}
onDescriptionUpdate={onDescriptionUpdate}
onShowDeletedTeamChange={toggleShowDeletedTeam}
onTeamExpand={fetchAllTeamsAdvancedDetails}