Skip to content

Commit 507ddd7

Browse files
committed
[DOP-22412] Improve Dataset node UX
1 parent 9f371f6 commit 507ddd7

File tree

7 files changed

+152
-43
lines changed

7 files changed

+152
-43
lines changed

src/components/lineage/nodes/dataset_node/DatasetNode.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const DatasetNode = (props: NodeProps<DatasetNode>): ReactElement => {
1717
let title = props.data.name;
1818
const subheader = `${props.data.location.type}://${props.data.location.name}`;
1919
if (title.includes("/")) {
20-
title = ".../" + title.substring(title.lastIndexOf("/") + 1);
20+
title = ".../" + title.split("/").slice(-2).join("/");
2121
}
2222

2323
const createPath = useCreatePath();

src/components/lineage/nodes/dataset_node/DatasetSchemaTable.tsx

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,124 @@
11
import {
2+
IconButton,
3+
Stack,
24
Table,
35
TableBody,
46
TableCell,
57
TableHead,
8+
TablePagination,
69
TableRow,
10+
TextField,
711
} from "@mui/material";
812
import { IORelationSchemaFieldV1 } from "@/dataProvider/types";
913
import { useTranslate } from "react-admin";
14+
import { useMemo, useState } from "react";
15+
import { Search } from "@mui/icons-material";
16+
import { paginateArray } from "../../utils/pagination";
17+
import { fieldMatchesText, flattenFields } from "./utils";
1018

1119
const DatasetSchemaTable = ({
1220
fields,
13-
level = 0,
21+
defaultRowsPerPage = 10,
1422
}: {
1523
fields: IORelationSchemaFieldV1[];
16-
level?: number;
24+
defaultRowsPerPage?: number;
1725
}) => {
1826
const translate = useTranslate();
1927

28+
const [page, setPage] = useState(0);
29+
const [rowsPerPage, setRowsPerPage] = useState(defaultRowsPerPage);
30+
const [showSearch, setShowSearch] = useState(false);
31+
const [search, setSearch] = useState("");
32+
33+
const filteredFields = useMemo(
34+
() =>
35+
flattenFields(fields).filter(
36+
(field) => !showSearch || fieldMatchesText(field, search),
37+
),
38+
[fields, showSearch, search],
39+
);
40+
41+
const fieldsToShow = paginateArray(filteredFields, page, rowsPerPage);
42+
43+
const rowsPerPageOptions = [
44+
5,
45+
10,
46+
25,
47+
50,
48+
100,
49+
{
50+
label: translate("resources.datasets.fields.schema.pagination.all"),
51+
value: -1,
52+
},
53+
];
54+
2055
return (
21-
<Table>
22-
<TableHead>
23-
<TableRow>
24-
<TableCell>
25-
{translate(
26-
"resources.datasets.fields.schema.field.name",
27-
)}
28-
</TableCell>
29-
<TableCell>
30-
{translate(
31-
"resources.datasets.fields.schema.field.type",
56+
<>
57+
<Stack
58+
direction="row"
59+
spacing={1}
60+
justifyContent={"flex-end"}
61+
className="nodrag nopan"
62+
>
63+
{showSearch && (
64+
<TextField
65+
id="search"
66+
type="search"
67+
autoFocus={true}
68+
placeholder={translate(
69+
"resources.datasets.fields.schema.search.placeholder",
3270
)}
33-
</TableCell>
34-
<TableCell>
35-
{translate(
36-
"resources.datasets.fields.schema.field.description",
37-
)}
38-
</TableCell>
39-
</TableRow>
40-
</TableHead>
41-
<TableBody>
42-
{fields.map((field) => (
43-
<>
44-
<TableRow key={`${level}.${field.name}.main`}>
45-
<TableCell>{field.name}</TableCell>
46-
<TableCell>{field.type}</TableCell>
47-
<TableCell>{field.description}</TableCell>
48-
</TableRow>
49-
{field.fields.length > 0 && (
50-
/* create nested table for nested fields */
51-
<TableRow key={`${level}.${field.name}.nested`}>
52-
<TableCell rowSpan={level + 1} />
53-
<DatasetSchemaTable
54-
fields={field.fields}
55-
level={level + 1}
56-
/>
71+
value={search}
72+
onChange={(e) => setSearch(e.target.value)}
73+
/>
74+
)}
75+
<IconButton
76+
aria-label={translate(
77+
"resources.datasets.fields.schema.search.name",
78+
)}
79+
onClick={() => setShowSearch(!showSearch)}
80+
>
81+
<Search />
82+
</IconButton>
83+
</Stack>
84+
<Table>
85+
<TableHead>
86+
<TableRow>
87+
<TableCell>
88+
{translate(
89+
"resources.datasets.fields.schema.field.name",
90+
)}
91+
</TableCell>
92+
<TableCell>
93+
{translate(
94+
"resources.datasets.fields.schema.field.type",
95+
)}
96+
</TableCell>
97+
</TableRow>
98+
</TableHead>
99+
<TableBody>
100+
{fieldsToShow.map((field) => (
101+
<>
102+
<TableRow key={`${field.name}.main`}>
103+
<TableCell>{field.name}</TableCell>
104+
<TableCell>{field.type}</TableCell>
57105
</TableRow>
58-
)}
59-
</>
60-
))}
61-
</TableBody>
62-
</Table>
106+
</>
107+
))}
108+
</TableBody>
109+
<TablePagination
110+
count={filteredFields.length}
111+
page={page}
112+
rowsPerPage={rowsPerPage}
113+
rowsPerPageOptions={rowsPerPageOptions}
114+
onPageChange={(e, pageNumber) => setPage(pageNumber)}
115+
onRowsPerPageChange={(e) =>
116+
setRowsPerPage(e.target.value as unknown as number)
117+
}
118+
className="nodrag nopan"
119+
/>
120+
</Table>
121+
</>
63122
);
64123
};
65124

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { IORelationSchemaFieldV1 } from "@/dataProvider/types";
2+
3+
export const fieldMatchesText = (
4+
field: IORelationSchemaFieldV1,
5+
searchText: string,
6+
): boolean => {
7+
const forSearch = searchText.toLowerCase();
8+
return (
9+
field.name.toLowerCase().includes(forSearch) ||
10+
(field.type ?? "").toLowerCase().includes(forSearch)
11+
);
12+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { IORelationSchemaFieldV1 } from "@/dataProvider/types";
2+
3+
export const flattenFields = (
4+
fields: IORelationSchemaFieldV1[],
5+
prefix: string = "",
6+
): IORelationSchemaFieldV1[] => {
7+
let result: IORelationSchemaFieldV1[] = [];
8+
for (const field of fields) {
9+
result.push(field);
10+
if (field.fields.length > 0) {
11+
// parent.child
12+
result = result.concat(
13+
flattenFields(field.fields, prefix + field.name + "."),
14+
);
15+
}
16+
}
17+
return result;
18+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { fieldMatchesText } from "./fieldMatchesText";
2+
import { flattenFields } from "./flattenFields";
3+
4+
export { fieldMatchesText, flattenFields };
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const paginateArray = <T>(
2+
array: T[],
3+
page: number,
4+
rowsPerPage: number,
5+
): T[] => {
6+
return rowsPerPage > 0
7+
? array.slice(page * rowsPerPage, (page + 1) * rowsPerPage)
8+
: array;
9+
};

src/i18n/en.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ const customEnglishMessages: TranslationMessages = {
8080
type: "Type",
8181
description: "Description",
8282
},
83+
search: {
84+
name: "Search",
85+
placeholder: "Filter by name",
86+
},
87+
pagination: {
88+
all: "All",
89+
},
8390
},
8491
},
8592
tabs: {

0 commit comments

Comments
 (0)