Skip to content

Commit 532b194

Browse files
atrakhConvex, Inc.
authored and
Convex, Inc.
committed
Add validator toopltip to ColumnHeader (#36455)
GitOrigin-RevId: a96d417d1f3fd67b0c27313e967ed3c0645858c9
1 parent 8654954 commit 532b194

File tree

3 files changed

+92
-58
lines changed

3 files changed

+92
-58
lines changed

npm-packages/dashboard-common/src/features/data/components/Table/ColumnHeader.tsx

Lines changed: 83 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import { columnWidthToString } from "@common/features/data/components/Table/Data
1515
import { Tooltip } from "@ui/Tooltip";
1616
import { cn } from "@ui/cn";
1717
import { DeploymentInfoContext } from "@common/lib/deploymentContext";
18+
import { documentValidatorForTable } from "@common/features/data/components/Table/utils/validators";
19+
import { displayObjectFieldSchema, prettier } from "@common/lib/format";
1820

1921
type ColumnHeaderProps = {
2022
column: HeaderGroup<GenericDocument>;
@@ -28,6 +30,8 @@ type ColumnHeaderProps = {
2830
isLastColumn: boolean;
2931
openContextMenu: DataCellProps["onOpenContextMenu"];
3032
sort?: "asc" | "desc";
33+
activeSchema: any | null;
34+
tableName: string;
3135
};
3236

3337
export function ColumnHeader({
@@ -42,6 +46,8 @@ export function ColumnHeader({
4246
isLastColumn,
4347
openContextMenu,
4448
sort,
49+
activeSchema,
50+
tableName,
4551
}: ColumnHeaderProps) {
4652
const canDragOrDrop = columnIndex !== 0 && !isResizingColumn;
4753

@@ -66,6 +72,23 @@ export function ColumnHeader({
6672

6773
const { densityValues } = useTableDensity();
6874
const width = columnWidthToString(column.getHeaderProps().style?.width);
75+
76+
// Get the validator information for the tooltip
77+
const documentValidator =
78+
activeSchema && documentValidatorForTable(activeSchema, tableName);
79+
const validatorTooltip =
80+
documentValidator?.type === "object" &&
81+
documentValidator.value[columnName] ? (
82+
<pre className="w-fit text-left">
83+
<code>
84+
{prettier(
85+
displayObjectFieldSchema(documentValidator.value[columnName]),
86+
40,
87+
).slice(0, -1)}
88+
</code>
89+
</pre>
90+
) : null;
91+
6992
return (
7093
<div
7194
key={column.getHeaderProps().key}
@@ -88,67 +111,69 @@ export function ColumnHeader({
88111
)}
89112
/>
90113
)}
91-
<div
92-
className="flex items-center space-x-2"
93-
ref={ref}
94-
style={{
95-
padding: `${densityValues.paddingY}px ${columnIndex === 0 ? "12" : densityValues.paddingX}px`,
96-
width,
97-
}}
98-
>
99-
{columnIndex === 0 ? (
100-
// Disable the "Select all" checkbox when filtering
101-
allRowsSelected === false &&
102-
hasFilters &&
103-
!isSelectionExhaustive ? null : (
104-
<Checkbox checked={allRowsSelected} onChange={toggleAll} />
105-
)
106-
) : column.Header === emptyColumnName ? (
107-
<i>empty</i>
108-
) : typeof column.Header === "string" &&
109-
identifierNeedsEscape(column.Header) ? (
110-
<span
111-
className={`before:text-content-primary before:content-['"'] after:text-content-primary after:content-['"']`}
112-
>
113-
{column.render("Header")}
114-
</span>
115-
) : (
116-
<div>{column.render("Header")}</div>
117-
)}
118-
{!column.disableResizing && (
119-
<div
120-
{...column.getResizerProps()}
121-
className="absolute top-0 z-20 inline-block h-full"
122-
style={{
123-
// @ts-expect-error bad typing in react-table
124-
...column.getResizerProps().style,
125-
width: densityValues.paddingX * (isLastColumn ? 1 : 2),
126-
right: isLastColumn ? 0 : -densityValues.paddingX,
127-
}}
128-
/>
129-
)}
130-
{column.Header !== "_creationTime" &&
131-
(column as unknown as { isDate: boolean }).isDate && (
132-
<Tooltip
133-
tip="Displaying numbers as dates. Hover or edit the cell by double-clicking see the unformatted value."
134-
side="top"
135-
align="start"
136-
className="flex items-center"
114+
<Tooltip tip={validatorTooltip}>
115+
<div
116+
className="flex items-center space-x-2"
117+
ref={ref}
118+
style={{
119+
padding: `${densityValues.paddingY}px ${columnIndex === 0 ? "12" : densityValues.paddingX}px`,
120+
width,
121+
}}
122+
>
123+
{columnIndex === 0 ? (
124+
// Disable the "Select all" checkbox when filtering
125+
allRowsSelected === false &&
126+
hasFilters &&
127+
!isSelectionExhaustive ? null : (
128+
<Checkbox checked={allRowsSelected} onChange={toggleAll} />
129+
)
130+
) : column.Header === emptyColumnName ? (
131+
<i>empty</i>
132+
) : typeof column.Header === "string" &&
133+
identifierNeedsEscape(column.Header) ? (
134+
<span
135+
className={`before:text-content-primary before:content-['"'] after:text-content-primary after:content-['"']`}
137136
>
138-
<QuestionMarkCircledIcon />
139-
</Tooltip>
137+
{column.render("Header")}
138+
</span>
139+
) : (
140+
<div>{column.render("Header")}</div>
140141
)}
141-
{sort && enableIndexFilters && (
142-
<Tooltip tip="You may change the sort order in the Filter & Sort menu.">
143-
<CaretUpIcon
144-
className={cn(
145-
"transition-all",
146-
sort === "asc" ? "" : "rotate-180",
147-
)}
142+
{!column.disableResizing && (
143+
<div
144+
{...column.getResizerProps()}
145+
className="absolute top-0 z-20 inline-block h-full"
146+
style={{
147+
// @ts-expect-error bad typing in react-table
148+
...column.getResizerProps().style,
149+
width: densityValues.paddingX * (isLastColumn ? 1 : 2),
150+
right: isLastColumn ? 0 : -densityValues.paddingX,
151+
}}
148152
/>
149-
</Tooltip>
150-
)}
151-
</div>
153+
)}
154+
{column.Header !== "_creationTime" &&
155+
(column as unknown as { isDate: boolean }).isDate && (
156+
<Tooltip
157+
tip="Displaying numbers as dates. Hover or edit the cell by double-clicking see the unformatted value."
158+
side="top"
159+
align="start"
160+
className="flex items-center"
161+
>
162+
<QuestionMarkCircledIcon />
163+
</Tooltip>
164+
)}
165+
{sort && enableIndexFilters && (
166+
<Tooltip tip="You may change the sort order in the Filter & Sort menu.">
167+
<CaretUpIcon
168+
className={cn(
169+
"transition-all",
170+
sort === "asc" ? "" : "rotate-180",
171+
)}
172+
/>
173+
</Tooltip>
174+
)}
175+
</div>
176+
</Tooltip>
152177
</div>
153178
);
154179
}

npm-packages/dashboard-common/src/features/data/components/Table/Table.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ export function Table({
252252
topBorderAnimation={topBorderAnimation}
253253
openContextMenu={openContextMenu}
254254
sort={sort}
255+
activeSchema={activeSchema}
256+
tableName={tableName}
255257
/>
256258
{/* Body */}
257259
<div

npm-packages/dashboard-common/src/features/data/components/Table/TableHeader.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import classNames from "classnames";
44
import omit from "lodash/omit";
55
import { ColumnHeader } from "@common/features/data/components/Table/ColumnHeader";
66
import { DataCellProps } from "@common/features/data/components/Table/DataCell/DataCell";
7+
import { SchemaJson } from "@common/lib/format";
78

89
export function TableHeader({
910
headerGroups,
@@ -16,6 +17,8 @@ export function TableHeader({
1617
reorder,
1718
openContextMenu,
1819
sort,
20+
activeSchema,
21+
tableName,
1922
}: {
2023
reorder(item: { index: number }, newIndex: number): void;
2124
headerGroups: HeaderGroup<GenericDocument>[];
@@ -30,6 +33,8 @@ export function TableHeader({
3033
order: "asc" | "desc";
3134
field: string;
3235
};
36+
activeSchema: SchemaJson | null;
37+
tableName: string;
3338
}) {
3439
return (
3540
<div className="group">
@@ -56,6 +61,8 @@ export function TableHeader({
5661
toggleAll={toggleAll}
5762
openContextMenu={openContextMenu}
5863
sort={sort.field === column.Header ? sort.order : undefined}
64+
activeSchema={activeSchema}
65+
tableName={tableName}
5966
/>
6067
))}
6168
</div>

0 commit comments

Comments
 (0)