Skip to content

Commit

Permalink
Moved result table column definition to dataset search file to allow …
Browse files Browse the repository at this point in the history
…custom custom rendering. Added nicer visuals for dataset status
  • Loading branch information
joaquinvanschoren committed Nov 17, 2023
1 parent fb7df54 commit 4739de3
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 52 deletions.
59 changes: 13 additions & 46 deletions app/src/components/search/ResultTable.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { DataGrid as MuiDataGrid } from "@mui/x-data-grid";
import { useEffect, useState } from "react";
import styled from "@emotion/styled";
import { Box } from "@mui/material";
import { useRouter } from "next/router";

const MAX_CELL_LENGTH = 75;
const BASE_PADDING = 1;

const DataGrid = styled(MuiDataGrid)`
& .MuiDataGrid-columnHeaders {
Expand All @@ -19,39 +17,8 @@ const DataGrid = styled(MuiDataGrid)`
}
`;

// Calculate a good table column width based on the content
const useAutoWidthColumns = (rows, columnOrder) => {
const [columnWidths, setColumnWidths] = useState({});
const context = document.createElement("canvas").getContext("2d");
context.font = "13px Roboto"; // Should match the DataGrid font

useEffect(() => {
const newColumnWidths = {};

columnOrder.forEach((fieldName) => {
let maxWidth = BASE_PADDING; // Start with base padding
rows.forEach((row) => {
let value = row[fieldName]?.raw ?? row[fieldName];
value = value && value.toString();
if (value && value.length > MAX_CELL_LENGTH) {
value = value.substring(0, MAX_CELL_LENGTH) + "…"; // Truncate the value
}
const textWidth = context.measureText(value || "").width;
maxWidth = Math.max(maxWidth, textWidth + BASE_PADDING); // Add padding to the text width
});

// Set a minimum width for the column to avoid too narrow columns for short content
newColumnWidths[fieldName] = Math.max(maxWidth, 100); // Minimum column width, adjust as necessary
});

setColumnWidths(newColumnWidths);
}, [rows, columnOrder]);

return columnWidths;
};

// Map the way ElasticSearch returns the data to the way the DataGrid expects it
const valueGetter = (fieldName) => (params) => {
export const valueGetter = (fieldName) => (params) => {
let value = params.row[fieldName]?.raw ?? params.row[fieldName];
if (typeof value === "string") {
// Remove quotes from string values
Expand Down Expand Up @@ -93,25 +60,25 @@ const renderCell = (params) => {
);
};

const ResultsTable = ({ results, columnOrder }) => {
const router = useRouter();
const columnWidths = useAutoWidthColumns(results, columnOrder);

// Check if there are results
if (results.length === 0) {
return <div>No results found</div>;
}

// Define the columns based on the keys from the results
const columns = columnOrder.map((fieldName) => {
// Builds a default column definition
export const buildDefaultColumns = (columnOrder) => {
return columnOrder.map((fieldName) => {
return {
field: fieldName,
headerName: fieldName.charAt(0).toUpperCase() + fieldName.slice(1),
width: columnWidths[fieldName] || 150, // Use the calculated width or a default value
valueGetter: valueGetter(fieldName),
renderCell: renderCell,
};
});
};

const ResultsTable = ({ results, columns }) => {
const router = useRouter();

// Check if there are results
if (results.length === 0) {
return <div>No results found</div>;
}

// Define the rows for the grid
const rows = results.map((result, index) => {
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/search/SearchContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ const SearchContainer = memo(
config,
sort_options,
search_facets,
columnOrder,
columns,
facet_aliases,
title,
type,
Expand Down Expand Up @@ -329,7 +329,7 @@ const SearchContainer = memo(
{view === "table" && (
<WithSearch mapContextToProps={({ results }) => ({ results })}>
{({ results }) => (
<ResultsTable results={results} columnOrder={columnOrder} />
<ResultsTable results={results} columns={columns} />
)}
</WithSearch>
)}
Expand Down
129 changes: 125 additions & 4 deletions app/src/pages/d/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ import { useNextRouting } from "../../utils/useNextRouting";

import DashboardLayout from "../../layouts/Dashboard";
import SearchContainer from "../../components/search/SearchContainer";
import { renderCell, valueGetter } from "../../components/search/ResultTable";

import Chip from "@mui/material/Chip";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faCheck,
faTriangleExclamation,
faRotate,
} from "@fortawesome/free-solid-svg-icons";

import searchConfig from "./searchConfig";

// Server-side translation
Expand All @@ -18,6 +28,46 @@ export async function getStaticProps(context) {
};
}

const getStatusChipProps = (status) => {
switch (status) {
case "active":
return {
label: "Verified",
icon: <FontAwesomeIcon icon={faCheck} />,
color: "success",
};
case "deactivated":
return {
label: "Deprecated",
icon: <FontAwesomeIcon icon={faTriangleExclamation} />,
color: "error",
};
case "in_preparation":
return {
label: "In Preparation",
icon: <FontAwesomeIcon icon={faRotate} />,
color: "warning",
};
default:
return {
label: "Unknown",
};
}
};

const renderStatus = (params) => {
const { label, icon, color, variant } = getStatusChipProps(params.value);
return (
<Chip
icon={icon}
label={label}
color={color}
size="small"
variant="outlined"
/>
);
};

const sort_options = [
{
name: "search.relevance",
Expand Down Expand Up @@ -91,17 +141,88 @@ const columnOrder = [
"tags",
];

// Controls how columns are rendered and manipulated in the table view
const columns = [
{
field: "data_id",
headerName: "Data_id",
valueGetter: valueGetter("data_id"),
renderCell: renderCell,
},
{
field: "name",
headerName: "Name",
valueGetter: valueGetter("name"),
renderCell: renderCell,
},
{
field: "version",
headerName: "Version",
valueGetter: valueGetter("version"),
renderCell: renderCell,
},
{
field: "status",
headerName: "Status",
valueGetter: valueGetter("status"),
renderCell: renderStatus,
type: "singleSelect",
valueOptions: ["active", "deactivated", "in_preparation"],
},
{
field: "description",
headerName: "Description",
valueGetter: valueGetter("description"),
renderCell: renderCell,
},
{
field: "creator",
headerName: "Creator",
valueGetter: valueGetter("creator"),
renderCell: renderCell,
},
{
field: "date",
headerName: "Date",
valueGetter: valueGetter("date"),
renderCell: renderCell,
},
{
field: "format",
headerName: "Format",
valueGetter: valueGetter("format"),
renderCell: renderCell,
},
{
field: "licence",
headerName: "Licence",
valueGetter: valueGetter("licence"),
renderCell: renderCell,
},
{
field: "url",
headerName: "Url",
valueGetter: valueGetter("url"),
renderCell: renderCell,
},
{
field: "tags",
headerName: "Tags",
valueGetter: valueGetter("tags"),
renderCell: renderCell,
},
];

function DataSearchContainer() {
// useNextRouting is a custom hook that will integrate with Next Router with Search UI config
// config is search-ui configuration.
// baseUrl is the path to the search page
const combinedConfig = useNextRouting(searchConfig, "<baseUrl>");
console.log("columns", JSON.stringify(columns));

return (
<SearchContainer
config={combinedConfig}
sort_options={sort_options}
search_facets={search_facets}
columnOrder={columnOrder}
columns={columns}
title="Datasets"
type="Dataset"
/>
Expand Down

0 comments on commit 4739de3

Please sign in to comment.