UI :- Converted html table to Antd table for Dashboard and PipelinesVersion (#8019)

* Converted html table to Antd table for Dashboard and Pipline Version

* remove dummy text

* change dashboardDetails and DatabaseSchema table to Antd

* remove tailwind css

* changes as per comments
This commit is contained in:
Ashish Gupta 2022-10-13 11:01:10 +05:30 committed by GitHub
parent 0e44f7d35d
commit 1f1943d2f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 294 additions and 311 deletions

View File

@ -11,13 +11,19 @@
* limitations under the License. * limitations under the License.
*/ */
import { Tooltip } from 'antd'; import { Space, Table, Tooltip } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import classNames from 'classnames';
import { compare } from 'fast-json-patch'; import { compare } from 'fast-json-patch';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';
import { EntityTags, ExtraInfo, TagOption } from 'Models'; import { EntityTags, ExtraInfo, TagOption } from 'Models';
import React, { RefObject, useCallback, useEffect, useState } from 'react'; import React, {
RefObject,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
import { EntityField } from '../../constants/feed.constants'; import { EntityField } from '../../constants/feed.constants';
@ -38,7 +44,6 @@ import {
getEntityName, getEntityName,
getEntityPlaceHolder, getEntityPlaceHolder,
getOwnerValue, getOwnerValue,
isEven,
} from '../../utils/CommonUtils'; } from '../../utils/CommonUtils';
import { getEntityFeedLink } from '../../utils/EntityUtils'; import { getEntityFeedLink } from '../../utils/EntityUtils';
import { getDefaultValue } from '../../utils/FeedElementUtils'; import { getDefaultValue } from '../../utils/FeedElementUtils';
@ -481,6 +486,121 @@ const DashboardDetails = ({
[paging] [paging]
); );
const tableColumn: ColumnsType<ChartType> = useMemo(
() => [
{
title: 'Chart Name',
dataIndex: 'chartName',
key: 'chartName',
width: 200,
render: (_, record) => (
<Link target="_blank" to={{ pathname: record.chartUrl }}>
<Space>
<span>{getEntityName(record as unknown as EntityReference)}</span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="16px"
/>
</Space>
</Link>
),
},
{
title: 'Chart Type',
dataIndex: 'chartType',
key: 'chartType',
width: 100,
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
width: 300,
render: (text, record, index) => (
<Space
className="w-full tw-group cursor-pointer"
data-testid="description">
<div>
{text ? (
<RichTextEditorPreviewer markdown={text} />
) : (
<span className="tw-no-description">No description</span>
)}
</div>
{!deleted && (
<Tooltip
title={
dashboardPermissions.EditAll
? 'Edit Description'
: NO_PERMISSION_FOR_ACTION
}>
<button
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
disabled={!dashboardPermissions.EditAll}
onClick={() => handleUpdateChart(record, index)}>
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="16px"
/>
</button>
</Tooltip>
)}
</Space>
),
},
{
title: 'Tags',
dataIndex: 'tags',
key: 'tags',
width: 300,
render: (text, record, index) => (
<div
className="relative tableBody-cell"
data-testid="tags-wrapper"
onClick={() => handleTagContainerClick(record, index)}>
{deleted ? (
<div className="tw-flex tw-flex-wrap">
<TagsViewer sizeCap={-1} tags={text || []} />
</div>
) : (
<TagsContainer
editable={editChartTags?.index === index}
isLoading={isTagLoading && editChartTags?.index === index}
selectedTags={text as EntityTags[]}
showAddTagButton={
dashboardPermissions.EditAll || dashboardPermissions.EditTags
}
size="small"
tagList={tagList}
type="label"
onCancel={() => {
handleChartTagSelection();
}}
onSelectionChange={(tags) => {
handleChartTagSelection(tags, {
chart: record,
index,
});
}}
/>
)}
</div>
),
},
],
[
dashboardPermissions.EditAll,
dashboardPermissions.EditTags,
editChartTags,
tagList,
deleted,
]
);
return ( return (
<PageContainer> <PageContainer>
<div className="tw-px-6 tw-w-full tw-h-full tw-flex tw-flex-col"> <div className="tw-px-6 tw-w-full tw-h-full tw-flex tw-flex-col">
@ -567,132 +687,14 @@ const DashboardDetails = ({
/> />
</div> </div>
</div> </div>
<div className="tw-table-responsive tw-table-container"> <Table
<table className="tw-w-full" data-testid="charts-table"> columns={tableColumn}
<thead> data-testid="charts-table"
<tr className="tableHead-row"> dataSource={charts}
<th className="tableHead-cell">Chart Name</th> pagination={false}
<th className="tableHead-cell">Chart Type</th> rowKey="id"
<th className="tableHead-cell">Description</th>
<th className="tableHead-cell tw-w-60">Tags</th>
</tr>
</thead>
<tbody className="tableBody">
{charts.map((chart, index) => (
<tr
className={classNames(
'tableBody-row',
!isEven(index + 1) ? 'odd-row' : null
)}
key={index}>
<td className="tableBody-cell">
<Link
target="_blank"
to={{ pathname: chart.chartUrl }}>
<span className="tw-flex">
<span className="tw-mr-1">
{getEntityName(
chart as unknown as EntityReference
)}
</span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="16px"
/>
</span>
</Link>
</td>
<td className="tableBody-cell">
{chart.chartType}
</td>
<td className="tw-group tableBody-cell tw-relative">
<div className="tw-inline-block">
<div
className="tw-cursor-pointer tw-flex"
data-testid="description">
<div>
{chart.description ? (
<RichTextEditorPreviewer
markdown={chart.description}
/>
) : (
<span className="tw-no-description">
No description
</span>
)}
</div>
{!deleted && (
<Tooltip
title={
dashboardPermissions.EditAll
? 'Edit Description'
: NO_PERMISSION_FOR_ACTION
}>
<button
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
disabled={!dashboardPermissions.EditAll}
onClick={() =>
handleUpdateChart(chart, index)
}>
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="16px"
/>
</button>
</Tooltip>
)}
</div>
</div>
</td>
<td
className="tw-group tw-relative tableBody-cell"
data-testid="tags-wrapper"
onClick={() =>
handleTagContainerClick(chart, index)
}>
{deleted ? (
<div className="tw-flex tw-flex-wrap">
<TagsViewer
sizeCap={-1}
tags={chart.tags || []}
/>
</div>
) : (
<TagsContainer
editable={editChartTags?.index === index}
isLoading={
isTagLoading &&
editChartTags?.index === index
}
selectedTags={chart.tags as EntityTags[]}
showAddTagButton={
dashboardPermissions.EditAll ||
dashboardPermissions.EditTags
}
size="small" size="small"
tagList={tagList}
type="label"
onCancel={() => {
handleChartTagSelection();
}}
onSelectionChange={(tags) => {
handleChartTagSelection(tags, {
chart,
index,
});
}}
/> />
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</> </>
)} )}
{activeTab === 2 && ( {activeTab === 2 && (

View File

@ -11,10 +11,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import classNames from 'classnames'; import classNames from 'classnames';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';
import { ExtraInfo } from 'Models'; import { ExtraInfo } from 'Models';
import React, { FC, useEffect, useState } from 'react'; import React, { FC, useEffect, useMemo, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
import { EntityField } from '../../constants/feed.constants'; import { EntityField } from '../../constants/feed.constants';
@ -22,9 +24,9 @@ import { OwnerType } from '../../enums/user.enum';
import { import {
ChangeDescription, ChangeDescription,
Dashboard, Dashboard,
EntityReference,
} from '../../generated/entity/data/dashboard'; } from '../../generated/entity/data/dashboard';
import { TagLabel } from '../../generated/type/tagLabel'; import { TagLabel } from '../../generated/type/tagLabel';
import { isEven } from '../../utils/CommonUtils';
import { import {
getDescriptionDiff, getDescriptionDiff,
getDiffByFieldName, getDiffByFieldName,
@ -212,6 +214,51 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
); );
}, [currentVersionData]); }, [currentVersionData]);
const tableColumn: ColumnsType<EntityReference> = useMemo(
() => [
{
title: 'Chart Name',
dataIndex: 'name',
key: 'name',
render: (text, record) => (
<Link target="_blank" to={{ pathname: text }}>
<Space>
<span>{record.displayName}</span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="16px"
/>
</Space>
</Link>
),
},
{
title: 'Chart Type',
dataIndex: 'type',
key: 'type',
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
render: (text) =>
text ? (
<RichTextEditorPreviewer markdown={text} />
) : (
<span className="tw-no-description">No description</span>
),
},
{
title: 'Tags',
dataIndex: 'tags',
key: 'tags',
},
],
[]
);
return ( return (
<PageContainer> <PageContainer>
<div <div
@ -249,60 +296,15 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
description={getDashboardDescription()} description={getDashboardDescription()}
/> />
</div> </div>
<div className="tw-table-responsive tw-my-6 tw-col-span-full tw-table-container"> <div className="m-y-md tw-col-span-full">
<table className="tw-w-full" data-testid="schema-table"> <Table
<thead> columns={tableColumn}
<tr className="tableHead-row"> data-testid="schema-table"
<th className="tableHead-cell">Chart Name</th> dataSource={(currentVersionData as Dashboard)?.charts}
<th className="tableHead-cell">Chart Type</th> pagination={false}
<th className="tableHead-cell">Description</th> rowKey="id"
<th className="tableHead-cell tw-w-60">Tags</th> size="small"
</tr>
</thead>
<tbody className="tableBody">
{(currentVersionData as Dashboard)?.charts?.map(
(chart, index) => (
<tr
className={classNames(
'tableBody-row',
!isEven(index + 1) ? 'odd-row' : null
)}
key={index}>
<td className="tableBody-cell">
<Link
target="_blank"
to={{ pathname: chart.name }}>
<span className="tw-flex">
<span className="tw-mr-1">
{chart.displayName}
</span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="16px"
/> />
</span>
</Link>
</td>
<td className="tableBody-cell">{chart.type}</td>
<td className="tw-group tableBody-cell tw-relative">
{chart.description ? (
<RichTextEditorPreviewer
markdown={chart.description}
/>
) : (
<span className="tw-no-description">
No description
</span>
)}
</td>
<td className="tw-group tw-relative tableBody-cell" />
</tr>
)
)}
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,10 +11,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import classNames from 'classnames'; import classNames from 'classnames';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';
import { ExtraInfo } from 'Models'; import { ExtraInfo } from 'Models';
import React, { FC, useEffect, useState } from 'react'; import React, { FC, useEffect, useMemo, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
import { EntityField } from '../../constants/feed.constants'; import { EntityField } from '../../constants/feed.constants';
@ -22,9 +24,9 @@ import { OwnerType } from '../../enums/user.enum';
import { import {
ChangeDescription, ChangeDescription,
Pipeline, Pipeline,
Task,
} from '../../generated/entity/data/pipeline'; } from '../../generated/entity/data/pipeline';
import { TagLabel } from '../../generated/type/tagLabel'; import { TagLabel } from '../../generated/type/tagLabel';
import { isEven } from '../../utils/CommonUtils';
import { import {
getDescriptionDiff, getDescriptionDiff,
getDiffByFieldName, getDiffByFieldName,
@ -212,6 +214,46 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
); );
}, [currentVersionData]); }, [currentVersionData]);
const tableColumn: ColumnsType<Task> = useMemo(
() => [
{
title: 'Task Name',
dataIndex: 'displayName',
key: 'displayName',
render: (text, record) => (
<Link target="_blank" to={{ pathname: record.taskUrl }}>
<Space>
<span>{text}</span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="16px"
/>
</Space>
</Link>
),
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
render: (text) =>
text ? (
<RichTextEditorPreviewer markdown={text} />
) : (
<span className="tw-no-description">No description</span>
),
},
{
title: 'Task Type',
dataIndex: 'taskType',
key: 'taskType',
},
],
[]
);
return ( return (
<PageContainer> <PageContainer>
<div <div
@ -246,74 +288,15 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
description={getPipelineDescription()} description={getPipelineDescription()}
/> />
</div> </div>
<div className="tw-table-responsive tw-my-6 tw-col-span-full tw-table-container"> <div className="m-y-md tw-col-span-full">
<table className="tw-w-full" data-testid="schema-table"> <Table
<thead> columns={tableColumn}
<tr className="tableHead-row"> data-testid="schema-table"
<th className="tableHead-cell">Task Name</th> dataSource={(currentVersionData as Pipeline)?.tasks}
<th className="tableHead-cell">Description</th> pagination={false}
<th className="tableHead-cell">Task Type</th> rowKey="name"
</tr> size="small"
</thead>
<tbody className="tableBody">
{(currentVersionData as Pipeline)?.tasks?.map(
(task, index) => (
<tr
className={classNames(
'tableBody-row',
!isEven(index + 1) ? 'odd-row' : null
)}
key={index}>
<td className="tableBody-cell">
<Link
target="_blank"
to={{ pathname: task.taskUrl }}>
<span className="tw-flex">
<span className="tw-mr-1">
{task.displayName}
</span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="16px"
/> />
</span>
</Link>
</td>
<td className="tw-group tableBody-cell tw-relative">
<div
className="tw-cursor-pointer hover:tw-underline tw-flex"
data-testid="description">
<div>
{task.description ? (
<RichTextEditorPreviewer
markdown={task.description}
/>
) : (
<span className="tw-no-description">
No description
</span>
)}
</div>
<button className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none">
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="16px"
/>
</button>
</div>
</td>
<td className="tableBody-cell">
{task.taskType}
</td>
</tr>
)
)}
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,9 +11,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { Col, Row, Space } from 'antd'; import { Col, Row, Space, Table as TableAntd } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import classNames from 'classnames';
import { compare, Operation } from 'fast-json-patch'; import { compare, Operation } from 'fast-json-patch';
import { startCase } from 'lodash'; import { startCase } from 'lodash';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
@ -23,6 +23,7 @@ import React, {
FunctionComponent, FunctionComponent,
RefObject, RefObject,
useEffect, useEffect,
useMemo,
useRef, useRef,
useState, useState,
} from 'react'; } from 'react';
@ -81,7 +82,6 @@ import jsonData from '../../jsons/en';
import { import {
getEntityName, getEntityName,
getPartialNameFromTableFQN, getPartialNameFromTableFQN,
isEven,
} from '../../utils/CommonUtils'; } from '../../utils/CommonUtils';
import { import {
databaseSchemaDetailsTabs, databaseSchemaDetailsTabs,
@ -516,60 +516,49 @@ const DatabaseSchemaPage: FunctionComponent = () => {
} }
}; };
const getSchemaTableList = () => { const tableColumn: ColumnsType<Table> = useMemo(
() => [
{
title: 'Table Name',
dataIndex: 'name',
key: 'name',
render: (text: string, record: Table) => {
return ( return (
<div className="tw-table-container tw-mb-4">
<table
className="tw-bg-white tw-w-full"
data-testid="databaseSchema-tables">
<thead data-testid="table-header">
<tr className="tableHead-row">
<th className="tableHead-cell" data-testid="header-name">
Table Name
</th>
<th className="tableHead-cell" data-testid="header-description">
Description
</th>
</tr>
</thead>
<tbody className="tableBody">
{tableData.length > 0 ? (
tableData.map((table, index) => (
<tr
className={classNames(
'tableBody-row',
!isEven(index + 1) ? 'odd-row' : null
)}
data-testid="table-column"
key={index}>
<td className="tableBody-cell">
<Link <Link
to={getEntityLink( to={getEntityLink(
EntityType.TABLE, EntityType.TABLE,
table.fullyQualifiedName as string record.fullyQualifiedName as string
)}> )}>
{table.name} {text}
</Link> </Link>
</td> );
<td className="tableBody-cell"> },
{table.description?.trim() ? ( },
<RichTextEditorPreviewer markdown={table.description} /> {
title: 'Description',
dataIndex: 'description',
key: 'description',
render: (text: string) =>
text?.trim() ? (
<RichTextEditorPreviewer markdown={text} />
) : ( ) : (
<span className="tw-no-description">No description</span> <span className="tw-no-description">No description</span>
)} ),
</td> },
</tr> ],
)) []
) : ( );
<tr className="tableBody-row">
<td className="tableBody-cell tw-text-center" colSpan={5}> const getSchemaTableList = () => {
No records found. return (
</td> <TableAntd
</tr> columns={tableColumn}
)} data-testid="databaseSchema-tables"
</tbody> dataSource={tableData}
</table> pagination={false}
</div> rowKey="id"
size="small"
/>
); );
}; };

View File

@ -11,6 +11,13 @@
* limitations under the License. * limitations under the License.
*/ */
.relative {
position: relative;
}
.absolute {
position: absolute;
}
.align-start { .align-start {
align-items: start; align-items: start;
} }