Skip to content

Commit

Permalink
Merge #133188
Browse files Browse the repository at this point in the history
133188: cluster-ui: misc v2 db pages styling adjustments r=xinhaoz a=xinhaoz

ui: regions label adjustments

- Ensure the regions label text isn't condensed to
1 character per row by providing a min width.
- Remove unnecessary widths on tables

Epic: none
Release note: None

------------------------------------------------------------

cluster-ui: misc v2 db pages styling adjustments

Misc formatting
- Fix page heading font styling
- Fix search bar on focus border being cut off
- Add `database` suffix to breadcrumb for db details page
- Format live data percentage by adding `live data` and
`total` as suffixes to numerator / denom respectively
- Don't show db and table breadcrumb as not found when
data is still being loaded
- Put reset index action in row outside / on top of table
- Add spinner state to refresh button when cached data is
refreshing

Table last updated/refreshed message & tooltip:
- Align data last refreshed time with page count
- Move full timestamp in table metadata tooltip
- Better error message formatting
- Show job progress when running

Grants
- Remove "Grants" header

Epic: [CRDB-37558](https://cockroachlabs.atlassian.net/browse/CRDB-37558)
Fixes: #132595

Release note (ui change): In the v2 database and db details
pages, the refresh button tooltip will now include the cache
refresh progress when the job is running as well as when the
update started.

Co-authored-by: Xin Hao Zhang <[email protected]>
  • Loading branch information
craig[bot] and xinhaoz committed Oct 24, 2024
2 parents 1256394 + dfc7d0f commit bc31b91
Show file tree
Hide file tree
Showing 24 changed files with 432 additions and 250 deletions.
2 changes: 0 additions & 2 deletions pkg/ui/workspaces/cluster-ui/src/common/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

:global(.crl-ant-tabs-tab) {
font-family: $font-family--base;
font-size: 16px;
line-height: 1.5;
letter-spacing: normal;
color: $colors--neutral-7;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2024 The Cockroach Authors.
//
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.

import { Row } from "antd";
import React from "react";

import { Bytes, Percentage } from "src/util";

type Props = {
// Float between 0-1.
liveBytes: number;
totalBytes: number;
};

export const LiveDataPercent: React.FC<Props> = ({ liveBytes, totalBytes }) => {
return (
<div>
<Row justify={"end"}>
{totalBytes ? Percentage(liveBytes, totalBytes, 1) : "0.0%"}
</Row>
<Row justify={"end"}>
{Bytes(liveBytes)} live data / {Bytes(totalBytes)} total
</Row>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
.container {
margin: 0.5rem;
width: fit-content;
min-width: 100px;
&:hover {
cursor: pointer;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ export const RegionLabel: React.FC<Props> = ({
<div className={styles["label-body"]}>
<Text strong>{region.label || "Unknown Region"}</Text>
{showCode && <Text>({region.code})</Text>}
<div>
<Badge count={nodes.length} className={styles.badge} />
</div>
<Badge count={nodes.length} className={styles.badge} />
</div>
</Tooltip>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,17 @@ describe("TableMetadataJobControl", () => {
jest.clearAllMocks();
});

it("renders the last refreshed time", () => {
it("renders the relative last refreshed time", () => {
render(
<TimezoneContext.Provider value="UTC">
<TableMetadataJobControl onJobComplete={mockOnJobComplete} />
</TimezoneContext.Provider>,
);

expect(screen.getByText(/Last refreshed:/)).toBeInTheDocument();
const lastCompletedRelativeTime = mockLastCompletedTime.fromNow();
expect(
screen.getByText(/Jan 01, 2024 at 12:00:00 UTC/),
screen.getByText(new RegExp(lastCompletedRelativeTime)),
).toBeInTheDocument();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.

import { RedoOutlined } from "@ant-design/icons";
import { Skeleton } from "antd";
import { LoadingOutlined, RedoOutlined } from "@ant-design/icons";
import { Skeleton, Spin } from "antd";
import React, { useCallback, useEffect } from "react";

import {
TableMetadataJobStatus,
triggerUpdateTableMetaJobApi,
useTableMetaUpdateJob,
} from "src/api/databases/tableMetaUpdateJobApi";
import { TABLE_METADATA_LAST_UPDATED_HELP } from "src/constants/tooltipMessages";
import Button from "src/sharedFromCloud/button";
import { Timestamp } from "src/timestamp";
import { DATE_WITH_SECONDS_FORMAT_24_TZ } from "src/util";
import { usePrevious } from "src/util/hooks";

import { Tooltip } from "../tooltip";
import { TableMetadataLastUpdatedTooltip } from "../tooltipMessages";

import styles from "./tableMetadataJobControl.module.scss";
import { TableMetadataJobProgress } from "./tableMetadataJobProgress";

type TableMetadataJobControlProps = {
// Callback for when the job has updated the metadata, i.e. the
Expand Down Expand Up @@ -80,34 +79,40 @@ export const TableMetadataJobControl: React.FC<
triggerUpdateTableMetaJob(false);
};

const durationText = jobStatus?.lastCompletedTime?.fromNow();
const isRunning = jobStatus?.currentStatus === TableMetadataJobStatus.RUNNING;
const refreshButtonTooltip = isRunning
? "Data is currently refreshing"
: "Refresh data";
const refreshButtonTooltip = isRunning ? (
<TableMetadataJobProgress
jobStartedTime={jobStatus?.lastStartTime}
jobProgressFraction={jobStatus?.progress}
/>
) : (
"Refresh data"
);

return (
<div className={styles["controls-container"]}>
<Skeleton loading={isLoading}>
<Tooltip title={TABLE_METADATA_LAST_UPDATED_HELP}>
Last refreshed:{" "}
<Timestamp
format={DATE_WITH_SECONDS_FORMAT_24_TZ}
time={jobStatus?.lastCompletedTime}
fallback={"Never"}
/>{" "}
{durationText && `(${durationText})`}
</Tooltip>
<TableMetadataLastUpdatedTooltip
timestamp={jobStatus?.lastCompletedTime}
>
{durationText => <div>Last refreshed: {durationText}</div>}
</TableMetadataLastUpdatedTooltip>
</Skeleton>
<Tooltip placement="top" title={refreshButtonTooltip}>
<div>
<Tooltip noUnderline placement="top" title={refreshButtonTooltip}>
<>
<Button
disabled={isRunning}
category={"icon-container"}
icon={<RedoOutlined />}
icon={
isRunning ? (
<Spin indicator={<LoadingOutlined spin />} size={"small"} />
) : (
<RedoOutlined />
)
}
onClick={onRefreshClick}
/>
</div>
</>
</Tooltip>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright 2024 The Cockroach Authors.
//
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.

.progress-list {
list-style-position: inside;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2024 The Cockroach Authors.
//
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.

import moment from "moment-timezone";
import React from "react";

import { Timestamp } from "src/timestamp";
import { DATE_WITH_SECONDS_FORMAT_24_TZ } from "src/util";

import styles from "./tableMetadataJobProgress.module.scss";

type Props = {
jobStartedTime: moment.Moment;
jobProgressFraction: number; // Between 0 and 1.
};

// This message is meant to be displayed when the job is running.
export const TableMetadataJobProgress: React.FC<Props> = ({
jobStartedTime,
jobProgressFraction,
}) => {
const percentDone = Math.round(jobProgressFraction * 100);
return (
<div>
Refreshing data
<ul className={styles["progress-list"]}>
<li>{percentDone}% done</li>
<li>
Started at{" "}
<Timestamp
time={jobStartedTime}
format={DATE_WITH_SECONDS_FORMAT_24_TZ}
/>
</li>
</ul>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

.title {
a {
font-size: inherit;
font: inherit;
color: inherit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
//
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.

import Link from "antd/es/typography/Link";
import React from "react";

import { tableStatsClusterSetting } from "src/util";
import { tableStatsClusterSetting } from "../../util";

export const AUTO_STATS_COLLECTION_HELP = (
<span>
Expand All @@ -17,5 +18,4 @@ export const AUTO_STATS_COLLECTION_HELP = (
</span>
);

export const TABLE_METADATA_LAST_UPDATED_HELP =
"Data is last refreshed automatically (per cluster setting) or manually.";
export * from "./tableMetadataLastUpdatedTooltip";
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright 2024 The Cockroach Authors.
//
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.

.table-metadata-tooltip-content {
column-gap: 8px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2024 The Cockroach Authors.
//
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.
import { Icon } from "@cockroachlabs/ui-components";
import { Row } from "antd";
import moment from "moment-timezone";
import React from "react";

import { Timestamp } from "../../timestamp";
import { DATE_WITH_SECONDS_FORMAT_24_TZ } from "../../util";
import { Tooltip } from "../tooltip";

import styles from "./tableMetadataLastUpdatedTooltip.module.scss";

const TABLE_METADATA_LAST_UPDATED_HELP =
"Data was last refreshed automatically (per cluster setting) or manually.";

type Props = {
timestamp?: moment.Moment | null;
children: (
formattedRelativeTime: string,
icon?: JSX.Element,
) => React.ReactNode;
errorMessage?: string;
};

const formatErrorMessage = (
errorMessage: string | null,
lastUpdatedTime: moment.Moment | null,
) => {
if (!errorMessage) {
return null;
}

return (
<>
Last refresh failed to retrieve data about this table. The data shown is
as of{" "}
<Timestamp
format={DATE_WITH_SECONDS_FORMAT_24_TZ}
time={lastUpdatedTime}
fallback={"Never"}
/>
.
<br />
Last refresh error: {errorMessage}
</>
);
};

export const TableMetadataLastUpdatedTooltip = ({
timestamp,
errorMessage,
children,
}: Props) => {
const durationText = timestamp?.fromNow() ?? "Never";
const icon = errorMessage ? (
<Icon fill={"warning"} iconName={"Caution"} />
) : (
<Icon fill="info" iconName={"InfoCircle"} />
);

const formattedErr = formatErrorMessage(errorMessage, timestamp);
return (
<Tooltip
title={
<div>
{formattedErr ?? (
<>
{timestamp && (
<Timestamp
format={DATE_WITH_SECONDS_FORMAT_24_TZ}
time={timestamp}
fallback={"Never"}
/>
)}
<br />
{TABLE_METADATA_LAST_UPDATED_HELP}
</>
)}
</div>
}
>
<Row className={styles["table-metadata-tooltip-content"]} align="middle">
{children(durationText, icon)}
</Row>
</Tooltip>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const DbGrantsView: React.FC = () => {
}, [databaseGrants]);

return (
<PageSection heading={"Grants"}>
<PageSection>
<GrantsTable data={dataWithKey ?? []} loading={isLoading} error={error} />
</PageSection>
);
Expand Down
20 changes: 9 additions & 11 deletions pkg/ui/workspaces/cluster-ui/src/databaseDetailsV2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ enum TabKeys {
export const DatabaseDetailsPageV2 = () => {
const { dbID: dbIdRouteParam } = useRouteParams();
const dbId = parseInt(dbIdRouteParam, 10);
const { data, isLoading, error } = useDatabaseMetadataByID(dbId);
const { data, isLoading } = useDatabaseMetadataByID(dbId);
const history = useHistory();
const location = useLocation();
const tab = queryByName(location, tabAttr) ?? TabKeys.TABLES;
Expand Down Expand Up @@ -57,25 +57,23 @@ export const DatabaseDetailsPageV2 = () => {
},
];

const dbName =
error?.status === 404 || !data
? "Database Not Found"
: data.metadata.dbName;
const dbName = isLoading ? (
<Skeleton paragraph={false} title={{ width: 100 }} />
) : (
data?.metadata.dbName ?? "Database Not Found"
);

const breadCrumbItems = [
{ name: "Databases", link: DB_PAGE_PATH },
{
name: dbName,
link: null,
name: <>Database: {dbName}</>,
link: "",
},
];

return (
<PageLayout>
<PageHeader
breadcrumbItems={breadCrumbItems}
title={<Skeleton loading={isLoading}>{dbName}</Skeleton>}
/>
<PageHeader breadcrumbItems={breadCrumbItems} title={dbName} />
<Tabs
defaultActiveKey={TabKeys.TABLES}
className={commonStyles("cockroach--tabs")}
Expand Down
Loading

0 comments on commit bc31b91

Please sign in to comment.