fix: general ui feedbacks (#12257)

* fix: ui feedbacks for lineage and breadcrumbs

* fix: add loader for entity popover card

* fix: feedbacks

* fix: layout issue

* fix: add expand collapse

* fix: feedbacks

* fix: explore url flicker

---------

Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
karanh37 2023-07-06 19:38:28 +05:30 committed by GitHub
parent 6e135302a7
commit 79d3e5d05c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 193 additions and 119 deletions

View File

@ -275,7 +275,13 @@ export const ActivityFeedTab = ({
label: (
<div className="d-flex justify-between">
<span>{t('label.all')}</span>
<span>{getCountBadge(allCount)}</span>
<span>
{getCountBadge(
allCount,
'',
activeTab === ActivityFeedTabs.ALL
)}
</span>
</div>
),
key: 'all',
@ -292,7 +298,13 @@ export const ActivityFeedTab = ({
label: (
<div className="d-flex justify-between">
<span>{t('label.task-plural')}</span>
<span>{getCountBadge(tasksCount)}</span>
<span>
{getCountBadge(
tasksCount,
'',
activeTab === ActivityFeedTabs.TASKS
)}
</span>
</div>
),
key: 'tasks',

View File

@ -125,7 +125,7 @@ const ContainerVersion: React.FC<ContainerVersionProp> = ({
label: <TabsLabel id={EntityTabs.SCHEMA} name={t('label.schema')} />,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -554,7 +554,7 @@ const DashboardDetails = ({
key: EntityTabs.DETAILS,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<div className="d-flex flex-col gap-4">
<DescriptionV1
description={dashboardDetails.description}

View File

@ -167,7 +167,7 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
),
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -273,7 +273,7 @@ const DataModelVersion: FC<DataModelVersionProp> = ({
label: <TabsLabel id={EntityTabs.MODEL} name={t('label.model')} />,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -161,7 +161,7 @@ const DataModelDetails = ({
const modelComponent = useMemo(() => {
return (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<div className="d-flex flex-col gap-4">
<DescriptionV1
description={description}

View File

@ -141,7 +141,7 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
label: <TabsLabel id={EntityTabs.SCHEMA} name={t('label.schema')} />,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -275,7 +275,9 @@ const EntityLineageComponent: FunctionComponent<EntityLineageProp> = ({
if (res && entityLineage) {
setNodeLoading((prev) => ({ ...prev, id: node.id, state: false }));
setLeafNode(res, pos);
setEntityLineage(getEntityLineage(entityLineage, res, pos));
const newLineageData = getEntityLineage(entityLineage, res, pos);
setEntityLineage(newLineageData);
setUpdatedLineageData(newLineageData);
}
} catch (err) {
setNodeLoading((prev) => ({ ...prev, id: node.id, state: false }));
@ -1260,6 +1262,7 @@ const EntityLineageComponent: FunctionComponent<EntityLineageProp> = ({
</div>
),
removeNodeHandler,
onNodeExpand: handleNodeExpand,
isEditMode,
isNewNode: true,
},

View File

@ -25,6 +25,7 @@
.ant-btn.ant-btn-background-ghost.expand-btn {
background-color: white;
box-shadow: none;
&:hover {
background-color: white;
}

View File

@ -26,7 +26,6 @@
padding-left: 8px;
padding-right: 8px;
border-radius: 4px;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.24);
position: relative;
font-size: 14px;
font-weight: 600;
@ -45,7 +44,6 @@
.custom-node-column-lineage {
background: @body-bg-color;
border: 1px solid;
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.16);
border-radius: 4px;
.custom-node-column-lineage-body {
@ -106,8 +104,6 @@
border: 1px solid @border-color;
border-radius: 4px;
background-color: @body-bg-color;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.custom-control-zoom-slide {
display: flex;

View File

@ -12,6 +12,7 @@
*/
import Icon, { DownOutlined } from '@ant-design/icons';
import { Button, Col, Dropdown, Row, Space, Tooltip, Typography } from 'antd';
import ButtonGroup from 'antd/lib/button/button-group';
import { ItemType } from 'antd/lib/menu/hooks/useItems';
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
import { ReactComponent as GlossaryIcon } from 'assets/svg/glossary.svg';
@ -390,45 +391,48 @@ const GlossaryHeader = ({
<div style={{ textAlign: 'right' }}>
<div>
{createButtons}
{selectedData && selectedData.version && (
<Button
className={classNames('m-l-xs', {
'text-primary border-primary': version,
})}
icon={<Icon component={VersionIcon} />}
onClick={handleVersionClick}>
<Typography.Text
className={classNames('m-l-xs', {
'text-primary': version,
})}>
{toString(selectedData.version)}
</Typography.Text>
</Button>
)}
{!isVersionView && (
<Dropdown
align={{ targetOffset: [-12, 0] }}
className="m-l-xs"
menu={{
items: manageButtonContent,
}}
open={showActions}
overlayClassName="glossary-manage-dropdown-list-container"
overlayStyle={{ width: '350px' }}
placement="bottomRight"
trigger={['click']}
onOpenChange={setShowActions}>
<Tooltip placement="right">
<Button
className="glossary-manage-dropdown-button tw-px-1.5"
data-testid="manage-button"
onClick={() => setShowActions(true)}>
<IconDropdown className="anticon self-center manage-dropdown-icon" />
</Button>
</Tooltip>
</Dropdown>
)}
<ButtonGroup className="p-l-xs" size="small">
{selectedData && selectedData.version && (
<Button
className={classNames('', {
'text-primary border-primary': version,
})}
icon={<Icon component={VersionIcon} />}
onClick={handleVersionClick}>
<Typography.Text
className={classNames('', {
'text-primary': version,
})}>
{toString(selectedData.version)}
</Typography.Text>
</Button>
)}
{!isVersionView && (
<Dropdown
align={{ targetOffset: [-12, 0] }}
className="m-l-xs"
menu={{
items: manageButtonContent,
}}
open={showActions}
overlayClassName="glossary-manage-dropdown-list-container"
overlayStyle={{ width: '350px' }}
placement="bottomRight"
trigger={['click']}
onOpenChange={setShowActions}>
<Tooltip placement="right">
<Button
className="glossary-manage-dropdown-button tw-px-1.5"
data-testid="manage-button"
onClick={() => setShowActions(true)}>
<IconDropdown className="anticon self-center manage-dropdown-icon" />
</Button>
</Tooltip>
</Dropdown>
)}
</ButtonGroup>
</div>
</div>
</Col>

View File

@ -44,7 +44,6 @@ function IngestionListTable({
ingestionData,
deleteSelection,
permissions,
pipelineNameColWidth,
pipelineType,
}: IngestionListTableProps) {
const { t } = useTranslation();
@ -130,7 +129,7 @@ function IngestionListTable({
title: t('label.name'),
dataIndex: 'name',
key: 'name',
width: pipelineNameColWidth ?? 500,
width: 500,
render: renderNameField,
},
{

View File

@ -385,7 +385,7 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
key: EntityTabs.FEATURES,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<div className="d-flex flex-col gap-4">
<DescriptionV1
description={mlModelDetail.description}

View File

@ -210,7 +210,7 @@ const MlModelVersion: FC<MlModelVersionProp> = ({
),
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -520,7 +520,7 @@ const PipelineDetails = ({
key: EntityTabs.TASKS,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -350,7 +350,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
),
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -19,8 +19,6 @@
@update-btn-hover-bg: #e2e2e2;
.custom-dropdown-render {
box-shadow: @box-shadow-base;
.ant-dropdown-menu {
box-shadow: none;
padding: 0px;

View File

@ -271,7 +271,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
key: EntityTabs.SCHEMA,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<div className="d-flex flex-col gap-4">
<DescriptionV1
description={topicDetails.description}

View File

@ -23,7 +23,10 @@ import {
Typography,
} from 'antd';
import Table, { ColumnsType } from 'antd/lib/table';
import { Key } from 'antd/lib/table/interface';
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
import { ReactComponent as DownUpArrowIcon } from 'assets/svg/ic-down-up-arrow.svg';
import { ReactComponent as UpDownArrowIcon } from 'assets/svg/ic-up-down-arrow.svg';
import classNames from 'classnames';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import SchemaEditor from 'components/schema-editor/SchemaEditor';
@ -81,10 +84,27 @@ const TopicSchemaFields: FC<TopicSchemaFieldsProps> = ({
const history = useHistory();
const { t } = useTranslation();
const [editFieldDescription, setEditFieldDescription] = useState<Field>();
const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]);
const [viewType, setViewType] = useState<SchemaViewType>(
SchemaViewType.FIELDS
);
const getAllRowKeys = (data: Field[]) => {
let keys: string[] = [];
data.forEach((item) => {
if (item.children && item.children.length > 0) {
keys.push(item.name);
keys = [...keys, ...getAllRowKeys(item.children)];
}
});
return keys;
};
const schemaAllRowKeys = useMemo(() => {
return getAllRowKeys(messageSchema?.schemaFields ?? []);
}, [messageSchema?.schemaFields]);
const getColumnName = (cell: Field) => {
const fqn = cell?.fullyQualifiedName || '';
const columnName = getPartialNameFromTopicFQN(fqn);
@ -130,6 +150,18 @@ const TopicSchemaFields: FC<TopicSchemaFieldsProps> = ({
}
};
const toggleExpandAll = () => {
if (expandedRowKeys.length > 0) {
setExpandedRowKeys([]);
} else {
setExpandedRowKeys(schemaAllRowKeys);
}
};
const handleExpandedRowsChange = (keys: readonly Key[]) => {
setExpandedRowKeys(keys as string[]);
};
const onUpdateDescriptionHandler = (cell: Field) => {
const field = EntityField.COLUMNS;
const value = getColumnName(cell);
@ -377,7 +409,7 @@ const TopicSchemaFields: FC<TopicSchemaFieldsProps> = ({
<>
{!isEmpty(messageSchema?.schemaFields) &&
showSchemaDisplayTypeSwitch && (
<Col span={24}>
<Col className="d-flex items-center justify-between" span={24}>
<Radio.Group value={viewType} onChange={handleViewChange}>
<Radio.Button value={SchemaViewType.FIELDS}>
{t('label.field-plural')}
@ -386,6 +418,24 @@ const TopicSchemaFields: FC<TopicSchemaFieldsProps> = ({
{t('label.text')}
</Radio.Button>
</Radio.Group>
<Button
className="text-primary rounded-4"
size="small"
type="text"
onClick={toggleExpandAll}>
<Space align="center" size={4}>
{expandedRowKeys.length === schemaAllRowKeys.length ? (
<DownUpArrowIcon color={DE_ACTIVE_COLOR} height="14px" />
) : (
<UpDownArrowIcon color={DE_ACTIVE_COLOR} height="14px" />
)}
{expandedRowKeys.length === schemaAllRowKeys.length
? t('label.collapse-all')
: t('label.expand-all')}
</Space>
</Button>
</Col>
)}
<Col span={24}>
@ -403,22 +453,26 @@ const TopicSchemaFields: FC<TopicSchemaFieldsProps> = ({
/>
)
) : (
<Table
bordered
className={className}
columns={columns}
data-testid="topic-schema-fields-table"
dataSource={messageSchema?.schemaFields}
expandable={{
...getTableExpandableConfig<Field>(),
rowExpandable: (record) => !isEmpty(record.children),
defaultExpandAllRows,
}}
pagination={false}
rowKey="name"
scroll={TABLE_SCROLL_VALUE}
size="small"
/>
<>
<Table
bordered
className={className}
columns={columns}
data-testid="topic-schema-fields-table"
dataSource={messageSchema?.schemaFields}
expandable={{
...getTableExpandableConfig<Field>(),
rowExpandable: (record) => !isEmpty(record.children),
onExpandedRowsChange: handleExpandedRowsChange,
defaultExpandAllRows,
expandedRowKeys,
}}
pagination={false}
rowKey="name"
scroll={TABLE_SCROLL_VALUE}
size="small"
/>
</>
)}
</Col>
</>

View File

@ -114,7 +114,7 @@ const TopicVersion: FC<TopicVersionProp> = ({
label: <TabsLabel id={EntityTabs.SCHEMA} name={t('label.schema')} />,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<Row gutter={[0, 16]}>
<Col span={24}>
<DescriptionV1

View File

@ -13,11 +13,13 @@
import { Space, Typography } from 'antd';
import { ReactComponent as IconTeamsGrey } from 'assets/svg/teams-grey.svg';
import { ReactComponent as IconUser } from 'assets/svg/user.svg';
import { getTeamAndUserDetailsPath, getUserPath } from 'constants/constants';
import { OwnerType } from 'enums/user.enum';
import { EntityReference } from 'generated/entity/data/table';
import { isUndefined } from 'lodash';
import React, { ReactNode, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { getEntityName } from 'utils/EntityUtils';
import ProfilePicture from '../ProfilePicture/ProfilePicture';
import { UserTeamSelectableList } from '../UserTeamSelectableList/UserTeamSelectableList.component';
@ -60,12 +62,16 @@ export const OwnerLabel = ({
{profilePicture}
{displayName ? (
<Typography.Link
className="font-normal text-xs"
<Link
className="text-primary font-medium text-xs no-underline"
data-testid="owner-link"
style={{ fontSize: '12px' }}>
to={
owner?.type === 'team'
? getTeamAndUserDetailsPath(owner?.name ?? '')
: getUserPath(owner?.name ?? '')
}>
{ownerDisplayName ?? displayName}
</Typography.Link>
</Link>
) : (
<Typography.Text
className="font-medium text-xs"

View File

@ -14,6 +14,7 @@
import { Popover } from 'antd';
import { EntityUnion } from 'components/Explore/explore.interface';
import ExploreSearchCard from 'components/ExploreV1/ExploreSearchCard/ExploreSearchCard';
import Loader from 'components/Loader/Loader';
import React, {
FC,
HTMLAttributes,
@ -48,6 +49,7 @@ const PopoverContent: React.FC<{
entityType: string;
}> = ({ entityFQN, entityType }) => {
const [entityData, setEntityData] = useState<EntityUnion>({} as EntityUnion);
const [loading, setLoading] = useState(false);
const getData = useCallback(() => {
const setEntityDetails = (entityDetail: EntityUnion) => {
@ -107,6 +109,7 @@ const PopoverContent: React.FC<{
}
if (promise) {
setLoading(true);
promise
.then((res) => {
setEntityDetails(res);
@ -114,6 +117,9 @@ const PopoverContent: React.FC<{
})
.catch(() => {
// do nothing
})
.finally(() => {
setLoading(false);
});
}
}, [entityType, entityFQN]);
@ -131,6 +137,10 @@ const PopoverContent: React.FC<{
onMouseOver();
}, [entityFQN]);
if (loading) {
return <Loader />;
}
return (
<ExploreSearchCard
id="tabledatacard"

View File

@ -12,8 +12,6 @@
*/
.anchor-drop-down {
--shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);
position: absolute;
transform-origin: top right;
z-index: 9999;
@ -24,6 +22,5 @@
width: 10rem;
padding: 0.3rem;
background-color: #ffffff;
box-shadow: 0 0 #0000, 0 0 #0000, 0 0 #0000, 0 0 #0000, var(--shadow);
outline: 0.09rem solid #0000000d;
}

View File

@ -129,7 +129,7 @@ const SearchedData: React.FC<SearchedDataProps> = ({
}
};
const { page, size } = useMemo(
const { page = 1, size = PAGE_SIZE } = useMemo(
() =>
Qs.parse(
location.search.startsWith('?')

View File

@ -602,7 +602,7 @@ const ContainerPage = () => {
key: EntityTabs.SCHEMA,
children: (
<Row gutter={[0, 16]} wrap={false}>
<Col className="p-t-sm m-l-lg" flex="auto">
<Col className="p-t-sm m-x-lg" flex="auto">
<div className="d-flex flex-col gap-4">
<DescriptionV1
description={description}

View File

@ -502,6 +502,7 @@ const DatabaseSchemaPage: FunctionComponent = () => {
</Link>
);
},
className: 'truncate w-max-500',
},
{
title: t('label.description'),

View File

@ -11,7 +11,6 @@
* limitations under the License.
*/
import { Card } from 'antd';
import { AxiosError } from 'axios';
import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component';
import { TitleBreadcrumbProps } from 'components/common/title-breadcrumb/title-breadcrumb.interface';
@ -177,13 +176,11 @@ const LineagePage = () => {
<PageLayoutV1 className="p-x-lg" pageTitle={t('label.lineage')}>
<div className="lineage-page-container page-container">
<TitleBreadcrumb titleLinks={titleBreadcrumb} />
<Card className="h-full" size="default">
<EntityLineageComponent
hasEditAccess
isFullScreen
entityType={entityType}
/>
</Card>
<EntityLineageComponent
hasEditAccess
isFullScreen
entityType={entityType}
/>
</div>
</PageLayoutV1>
);

View File

@ -431,7 +431,7 @@ const TableDetailsPageV1 = () => {
gutter={[0, 16]}
id="schemaDetails"
wrap={false}>
<Col className="p-t-sm m-l-lg tab-content-height" flex="auto">
<Col className="p-t-sm m-l-lg tab-content-height p-r-lg" flex="auto">
<div className="d-flex flex-col gap-4">
<DescriptionV1
description={tableDetails?.description}

View File

@ -223,8 +223,10 @@ const ExplorePageV1: FunctionComponent = () => {
}, [parsedSearch.size]);
useEffect(() => {
handlePageChange(page, size);
}, [page, size]);
if (!isEmpty(parsedSearch)) {
handlePageChange(page, size);
}
}, [page, size, parsedSearch]);
const showDeleted = useMemo(() => {
const showDeletedParam = parsedSearch.showDeleted;

View File

@ -369,10 +369,13 @@ a[href].link-text-grey,
font-size: inherit !important;
color: @text-grey-muted !important;
}
}
.link-title:hover {
text-decoration: none !important;
.link-title:hover {
color: @primary-color !important;
text-decoration: none !important;
}
.link-title.inactive-link:hover {
color: @text-grey-muted !important;
}
}
// lineage
@ -435,9 +438,8 @@ a[href].link-text-grey,
}
.entity-tag-right-panel-container {
height: @entity-details-tab-height;
overflow-y: scroll;
overflow-y: auto;
border-left: @global-border;
margin-left: 20px;
padding: 12px 8px 0 8px;
}

View File

@ -13,7 +13,6 @@
@import url('../variables.less');
@switch-bg-color-primary: rgb(107 114 128 / 15%);
@switch-bg-color-active: rgb(244, 240, 253);
@switch-border-color: rgba(107, 114, 128, 1);
.ant-switch {
@ -28,7 +27,7 @@
}
.ant-switch-checked {
background: @switch-bg-color-active;
background: @white;
border-color: @primary-color;
.ant-switch-handle::before {
background-color: @primary-color;

View File

@ -52,6 +52,10 @@
margin-right: @margin-sm;
margin-left: @margin-sm;
}
.m-x-lg {
margin-right: @margin-lg;
margin-left: @margin-lg;
}
.m-x-md {
margin-right: @margin-md;
margin-left: @margin-md;

View File

@ -45,7 +45,7 @@
@grey-5: #f4f6f9;
@text-grey-muted: @grey-4;
@font-size-base: 14px;
@box-shadow-base: 0px 2px 10px rgba(0, 0, 0, 0.12);
@box-shadow-base: none;
@white: #fff;
@border-radius-base: 4px;
@checkbox-size: 14px;

View File

@ -1145,12 +1145,6 @@ div.ant-typography-ellipsis-custom {
padding-right: 60px !important;
}
/* antd switch css */
.ant-switch-checked {
background: #0968da;
}
/* antd switch css */
.ant-empty-tasks {
margin-top: 32px;
}
@ -1163,11 +1157,6 @@ div.ant-typography-ellipsis-custom {
.activity-feed-card-text pre {
white-space: pre-wrap; /* Since CSS 2.1 */
}
/* Feed text pre tag CSS */
.ant-switch-checked {
background: rgb(244, 240, 253);
}
/* 64 header + ( 16 + 16 )spacing Y = 96*/
.left-panel-container {

View File

@ -133,7 +133,7 @@ export const getGlobalSettingsMenuWithPermission = (
icon: <TableIcon className="side-panel-icons" />,
},
{
label: i18next.t('label.messaging-plural'),
label: i18next.t('label.messaging'),
isProtected: userPermissions.hasViewPermissions(
ResourceEntity.MESSAGING_SERVICE,
permissions