mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-11 00:35:22 +00:00
feat(ui): Update Profiler components for improved styling and functionality
This commit is contained in:
parent
3132d61efc
commit
d4683a2e91
@ -43,9 +43,3 @@
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.profiler-latest-value {
|
||||
.ant-statistic-title {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ export interface ProfilerDetailsCardProps {
|
||||
isLoading?: boolean;
|
||||
noDataPlaceholderText?: ReactNode;
|
||||
children?: ReactNode;
|
||||
chartType?: 'line' | 'area';
|
||||
}
|
||||
|
||||
export enum TableProfilerTab {
|
||||
@ -78,6 +79,7 @@ export interface ProfilerLatestValueProps {
|
||||
information: MetricChartType['information'];
|
||||
tickFormatter?: string;
|
||||
stringValue?: boolean;
|
||||
onClick?: (dataKey: string) => void;
|
||||
}
|
||||
|
||||
export type TestCaseAction = {
|
||||
|
@ -11,15 +11,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card, Col, Row, Typography } from 'antd';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import React, { Fragment, useMemo, useState } from 'react';
|
||||
import {
|
||||
Area,
|
||||
Brush,
|
||||
CartesianGrid,
|
||||
Legend,
|
||||
LegendProps,
|
||||
ComposedChart,
|
||||
Line,
|
||||
LineChart,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
@ -47,7 +53,9 @@ const ProfilerDetailsCard: React.FC<ProfilerDetailsCardProps> = ({
|
||||
title,
|
||||
isLoading,
|
||||
noDataPlaceholderText,
|
||||
chartType = 'line',
|
||||
}: ProfilerDetailsCardProps) => {
|
||||
const theme = useTheme();
|
||||
const { data, information } = chartCollection;
|
||||
const [activeKeys, setActiveKeys] = useState<string[]>([]);
|
||||
const { showBrush, endIndex } = useMemo(() => {
|
||||
@ -57,38 +65,60 @@ const ProfilerDetailsCard: React.FC<ProfilerDetailsCardProps> = ({
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
const handleClick: LegendProps['onClick'] = (event) => {
|
||||
const handleClick = (dataKey: string) => {
|
||||
setActiveKeys((prevActiveKeys) =>
|
||||
updateActiveChartFilter(event.dataKey, prevActiveKeys)
|
||||
updateActiveChartFilter(dataKey, prevActiveKeys)
|
||||
);
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <Skeleton height={380} variant="rounded" width="100%" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="shadow-none global-border-radius"
|
||||
data-testid="profiler-details-card-container"
|
||||
loading={isLoading}>
|
||||
<Row gutter={[16, 16]}>
|
||||
{title && (
|
||||
<Col span={24}>
|
||||
<Typography.Title level={5}>{title}</Typography.Title>
|
||||
</Col>
|
||||
)}
|
||||
<Col span={4}>
|
||||
<Box>
|
||||
{title && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: '16px',
|
||||
color: theme.palette.grey[900],
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
mb: 3,
|
||||
}}
|
||||
variant="h6">
|
||||
{title}
|
||||
</Typography>
|
||||
)}
|
||||
<Card
|
||||
data-testid="profiler-details-card-container"
|
||||
sx={{
|
||||
p: 4,
|
||||
borderRadius: '10px',
|
||||
border: `1px solid ${theme.palette.grey[200]}`,
|
||||
boxShadow: 'none',
|
||||
}}>
|
||||
<Stack spacing={4}>
|
||||
<ProfilerLatestValue
|
||||
information={information}
|
||||
tickFormatter={tickFormatter}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={20}>
|
||||
|
||||
{data.length > 0 ? (
|
||||
<ResponsiveContainer
|
||||
className="custom-legend"
|
||||
debounce={200}
|
||||
id={`${name}_graph`}
|
||||
minHeight={300}>
|
||||
<LineChart className="w-full" data={data} margin={{ left: 16 }}>
|
||||
<CartesianGrid stroke={GRAPH_BACKGROUND_COLOR} />
|
||||
<ComposedChart
|
||||
className="w-full"
|
||||
data={data}
|
||||
margin={{ left: 16 }}>
|
||||
<CartesianGrid
|
||||
stroke={GRAPH_BACKGROUND_COLOR}
|
||||
strokeDasharray="3 3"
|
||||
vertical={false}
|
||||
/>
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
padding={{ left: 16, right: 16 }}
|
||||
@ -116,20 +146,37 @@ const ProfilerDetailsCard: React.FC<ProfilerDetailsCardProps> = ({
|
||||
}
|
||||
/>
|
||||
{information.map((info) => (
|
||||
<Line
|
||||
dataKey={info.dataKey}
|
||||
hide={
|
||||
activeKeys.length
|
||||
? !activeKeys.includes(info.dataKey)
|
||||
: false
|
||||
}
|
||||
key={info.dataKey}
|
||||
name={info.title}
|
||||
stroke={info.color}
|
||||
type={curveType ?? 'monotone'}
|
||||
/>
|
||||
<Fragment key={info.dataKey}>
|
||||
{chartType === 'area' && (
|
||||
<Area
|
||||
dataKey={info.dataKey}
|
||||
fill={info.color}
|
||||
fillOpacity={0.1}
|
||||
hide={
|
||||
activeKeys.length
|
||||
? !activeKeys.includes(info.dataKey)
|
||||
: false
|
||||
}
|
||||
key={info.dataKey}
|
||||
name={info.title}
|
||||
stroke={info.color}
|
||||
type={curveType ?? 'monotone'}
|
||||
/>
|
||||
)}
|
||||
<Line
|
||||
dataKey={info.dataKey}
|
||||
hide={
|
||||
activeKeys.length
|
||||
? !activeKeys.includes(info.dataKey)
|
||||
: false
|
||||
}
|
||||
key={info.dataKey}
|
||||
name={info.title}
|
||||
stroke={info.color}
|
||||
type={curveType ?? 'monotone'}
|
||||
/>
|
||||
</Fragment>
|
||||
))}
|
||||
<Legend onClick={handleClick} />
|
||||
{showBrush && (
|
||||
<Brush
|
||||
data={data}
|
||||
@ -139,21 +186,17 @@ const ProfilerDetailsCard: React.FC<ProfilerDetailsCardProps> = ({
|
||||
padding={{ left: 16, right: 16 }}
|
||||
/>
|
||||
)}
|
||||
</LineChart>
|
||||
</ComposedChart>
|
||||
</ResponsiveContainer>
|
||||
) : (
|
||||
<Row align="middle" className="h-full w-full" justify="center">
|
||||
<Col>
|
||||
<ErrorPlaceHolder
|
||||
className="mt-0-important"
|
||||
placeholderText={noDataPlaceholderText}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<ErrorPlaceHolder
|
||||
className="mt-0-important"
|
||||
placeholderText={noDataPlaceholderText}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Space, Statistic, Typography } from 'antd';
|
||||
import { Box, Stack, Typography, useTheme } from '@mui/material';
|
||||
import { isUndefined } from 'lodash';
|
||||
import { getStatisticsDisplayValue } from '../../../../utils/CommonUtils';
|
||||
import '../ProfilerDashboard/profiler-dashboard.less';
|
||||
@ -21,7 +21,10 @@ const ProfilerLatestValue = ({
|
||||
information,
|
||||
tickFormatter,
|
||||
stringValue = false,
|
||||
onClick,
|
||||
}: ProfilerLatestValueProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const getLatestValue = (value?: number | string) => {
|
||||
if (isUndefined(value)) {
|
||||
return '--';
|
||||
@ -35,23 +38,50 @@ const ProfilerLatestValue = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<Space data-testid="data-summary-container" direction="vertical" size={16}>
|
||||
<Stack
|
||||
data-testid="data-summary-container"
|
||||
direction="row"
|
||||
spacing={4}
|
||||
sx={{
|
||||
width: '100%',
|
||||
backgroundColor: theme.palette.grey[50],
|
||||
borderRadius: '10px',
|
||||
p: '16px 30px',
|
||||
}}>
|
||||
{information.map((info) => (
|
||||
<Statistic
|
||||
className="profiler-latest-value"
|
||||
<Box
|
||||
key={info.title}
|
||||
title={
|
||||
<Typography.Text
|
||||
className="text-grey-body break-all"
|
||||
data-testid="title">
|
||||
{info.title}
|
||||
</Typography.Text>
|
||||
}
|
||||
value={getLatestValue(info.latestValue)}
|
||||
valueStyle={{ color: info.color, fontSize: '18px', fontWeight: 700 }}
|
||||
/>
|
||||
sx={{
|
||||
cursor: onClick ? 'pointer' : 'default',
|
||||
}}
|
||||
onClick={() => onClick?.(info.dataKey)}>
|
||||
<Typography
|
||||
className="break-all"
|
||||
data-testid="title"
|
||||
sx={{
|
||||
color: theme.palette.grey[700],
|
||||
fontSize: '12px',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
borderLeft: `4px solid ${info.color}`,
|
||||
paddingLeft: '8px',
|
||||
lineHeight: '12px',
|
||||
mb: 1,
|
||||
}}>
|
||||
{info.title}
|
||||
</Typography>
|
||||
<Typography
|
||||
className="break-all"
|
||||
data-testid="value"
|
||||
sx={{
|
||||
color: theme.palette.grey[900],
|
||||
fontSize: '18px',
|
||||
fontWeight: 700,
|
||||
}}>
|
||||
{getLatestValue(info.latestValue)}
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Space>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -11,8 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Grid, Stack } from '@mui/material';
|
||||
import { Col } from 'antd';
|
||||
import { Box, Grid, Stack } from '@mui/material';
|
||||
import { AxiosError } from 'axios';
|
||||
import { pick } from 'lodash';
|
||||
import { DateRangeObject } from 'Models';
|
||||
@ -220,50 +219,49 @@ const TableProfilerChart = ({
|
||||
{showHeader && (
|
||||
<>
|
||||
{!isSummaryLoading && !isProfilingEnabled && (
|
||||
<Col span={24}>
|
||||
<Box>
|
||||
<NoProfilerBanner />
|
||||
</Col>
|
||||
</Box>
|
||||
)}
|
||||
<Col span={24}>
|
||||
<Grid container spacing={5}>
|
||||
{overallSummary?.map((summary) => (
|
||||
<Grid key={summary.title} size="grow">
|
||||
<SummaryCardV1
|
||||
extra={summary.extra}
|
||||
icon={summary.icon}
|
||||
isLoading={isSummaryLoading}
|
||||
title={summary.title}
|
||||
value={summary.value}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Col>
|
||||
|
||||
<Grid container spacing={5}>
|
||||
{overallSummary?.map((summary) => (
|
||||
<Grid key={summary.title} size="grow">
|
||||
<SummaryCardV1
|
||||
extra={summary.extra}
|
||||
icon={summary.icon}
|
||||
isLoading={isSummaryLoading}
|
||||
title={summary.title}
|
||||
value={summary.value}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
<Col data-testid="row-metrics" span={24}>
|
||||
<Box data-testid="row-metrics">
|
||||
<ProfilerDetailsCard
|
||||
chartCollection={rowCountMetrics}
|
||||
curveType="stepAfter"
|
||||
chartType="area"
|
||||
isLoading={isTableProfilerLoading}
|
||||
name="rowCount"
|
||||
noDataPlaceholderText={noProfilerMessage}
|
||||
title={t('label.data-volume')}
|
||||
/>
|
||||
</Col>
|
||||
</Box>
|
||||
{showSystemMetrics && (
|
||||
<>
|
||||
<Col span={24}>{operationDateMetricsCard}</Col>
|
||||
<Col span={24}>{operationMetricsCard}</Col>
|
||||
<Box>{operationDateMetricsCard}</Box>
|
||||
<Box>{operationMetricsCard}</Box>
|
||||
</>
|
||||
)}
|
||||
<Col span={24}>
|
||||
<Box>
|
||||
<CustomMetricGraphs
|
||||
customMetrics={customMetrics}
|
||||
customMetricsGraphData={tableCustomMetricsProfiling}
|
||||
isLoading={isTableProfilerLoading || isSummaryLoading}
|
||||
/>
|
||||
</Col>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
@ -27,7 +27,7 @@ export const TEXT_BODY_COLOR = '#37352F';
|
||||
export const TEXT_GREY_MUTED = '#757575';
|
||||
export const SUCCESS_COLOR = '#008376';
|
||||
export const DE_ACTIVE_COLOR = '#6B7280';
|
||||
export const GRAPH_BACKGROUND_COLOR = '#f5f5f5';
|
||||
export const GRAPH_BACKGROUND_COLOR = '#E9EAEB';
|
||||
export const GRAYED_OUT_COLOR = '#959595';
|
||||
export const BORDER_COLOR = '#0000001a';
|
||||
export const BLACK_COLOR = '#000000';
|
||||
|
Loading…
x
Reference in New Issue
Block a user