From 212e95cdced93621f3cda56aa01b7eba0d51bfe9 Mon Sep 17 00:00:00 2001 From: joaquinvanschoren Date: Thu, 23 Nov 2023 23:34:49 +0100 Subject: [PATCH] started generalizing search to other entity types --- app/src/components/TableView.js | 28 ------- app/src/components/search/ResultCard.js | 4 +- app/src/components/search/ResultTable.js | 88 +++++++++++++++++++++- app/src/components/sidebar/navItems.js | 20 ++--- app/src/pages/collections/runs.js | 13 +--- app/src/pages/collections/tasks.js | 13 +--- app/src/pages/d/index.js | 6 +- app/src/pages/d/search.js | 85 ++------------------- app/src/pages/f/[flowId].js | 42 +++++++++++ app/src/pages/f/index.js | 5 -- app/src/pages/measures/data.js | 11 +-- app/src/pages/measures/evaluation.js | 11 +-- app/src/pages/measures/procedures.js | 11 +-- app/src/pages/{u/index.js => r/[runId].js} | 80 ++++++++++---------- app/src/pages/r/index.js | 5 -- app/src/pages/t/[taskId].js | 42 +++++++++++ app/src/pages/t/index.js | 7 +- app/src/pages/t/search.js | 73 ++++++++++++++++++ app/src/pages/t/searchConfig.js | 40 ++++++++++ app/src/pages/u/[userId].js | 26 ------- 20 files changed, 366 insertions(+), 244 deletions(-) delete mode 100644 app/src/components/TableView.js create mode 100644 app/src/pages/f/[flowId].js rename app/src/pages/{u/index.js => r/[runId].js} (53%) create mode 100644 app/src/pages/t/[taskId].js create mode 100644 app/src/pages/t/search.js create mode 100644 app/src/pages/t/searchConfig.js delete mode 100644 app/src/pages/u/[userId].js diff --git a/app/src/components/TableView.js b/app/src/components/TableView.js deleted file mode 100644 index 95fc8208..00000000 --- a/app/src/components/TableView.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; - -import { Box } from "@mui/material"; -import { DataGrid } from "@mui/x-data-grid"; -import { useDemoData } from "@mui/x-data-grid-generator"; - -function TableView() { - const { data } = useDemoData({ - dataSet: "Commodity", - rowLength: 100000, - editable: true, - }); - console.log(data); - return ( - - - - ); -} - -export default TableView; diff --git a/app/src/components/search/ResultCard.js b/app/src/components/search/ResultCard.js index d99bef97..1062f1ec 100644 --- a/app/src/components/search/ResultCard.js +++ b/app/src/components/search/ResultCard.js @@ -218,14 +218,14 @@ const ResultCard = ({ result }) => { subheader={result.bio.raw} /> )} - {type !== "user" && ( + {type !== "user" && type !== "task" && ( <ColoredIcon color={color} icon={icon} fixedWidth /> {"\u00A0\u00A0"} {result.name.raw} )} - {type !== "user" && result.description.raw && ( + {type !== "user" && type !== "task" && result.description.raw && ( )} {stats !== undefined && ( diff --git a/app/src/components/search/ResultTable.js b/app/src/components/search/ResultTable.js index 8ed069a6..d6dea5d1 100644 --- a/app/src/components/search/ResultTable.js +++ b/app/src/components/search/ResultTable.js @@ -4,9 +4,13 @@ import { Box, IconButton, Snackbar } from "@mui/material"; import { useRouter } from "next/router"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React from "react"; -import { faCopy } from "@fortawesome/free-solid-svg-icons"; +import { faCopy, faEllipsis } from "@fortawesome/free-solid-svg-icons"; import { useTranslation } from "next-i18next"; +import Teaser from "../../components/search/Teaser"; +import TimeAgo from "react-timeago"; +import Chip from "@mui/material/Chip"; + const MAX_CELL_LENGTH = 75; const DataGrid = styled(MuiDataGrid)` @@ -105,6 +109,88 @@ export const copyCell = (setOpen) => { return CopyCellComponent; }; +// Renders chips in table view +// Higher-order component to pass the `getChipProps` function +export const renderChips = (getChipProps) => { + const RenderChips = (params) => { + const { label, icon, color } = getChipProps(params.value); + return ( +
+ +
+ ); + }; + + // Assign a display name for DevTools + RenderChips.displayName = `RenderChips`; + + return RenderChips; +}; + +export const renderTags = (params) => { + const { value } = params; + + // Return nothing if the label is empty + if (!value) { + return null; + } + + // Split the label by commas to create an array of tags + const labels = value + .split(",") + .map((label) => label.trim()) + .filter((label) => label); + + // Determine if there are more than 3 labels + const hasMore = labels.length > 3; + + // Slice the array to the first 3 labels if there are more than 3 + const visibleLabels = hasMore ? labels.slice(0, 3) : labels; + + // Map each tag to a Chip component and add a margin for spacing + const chips = visibleLabels.map((label, index) => ( + + )); + + return ( +
+ {chips} + {hasMore && ( + } + size="small" + variant="outlined" + sx={{ paddingLeft: "8px" }} // Match the margin of other chips + /> + )} +
+ ); +}; + +export const renderDate = (params) => { + return ; +}; + +export const renderDescription = (params) => { + return ( +
+ +
+ ); +}; + const ResultsTable = ({ results, columns }) => { const router = useRouter(); const [open, setOpen] = React.useState(false); // Snackbar diff --git a/app/src/components/sidebar/navItems.js b/app/src/components/sidebar/navItems.js index 82e4fb43..858ebe8e 100644 --- a/app/src/components/sidebar/navItems.js +++ b/app/src/components/sidebar/navItems.js @@ -5,17 +5,17 @@ const openmlSection = [ badge: "100", }, { - href: "/t", + href: "/t/search", title: "sidebar.tasks", badge: "100", }, { - href: "/f", + href: "/f/search", title: "sidebar.flows", badge: "100", }, { - href: "/r", + href: "/r/search", title: "sidebar.runs", badge: "100", }, @@ -24,12 +24,12 @@ const openmlSection = [ title: "sidebar.collections", children: [ { - href: "/collections/tasks", + href: "/collections/tasks/search", title: "sidebar.tasks", badge: "100", }, { - href: "/collections/runs", + href: "/collections/runs/search", title: "sidebar.runs", badge: "100", }, @@ -40,12 +40,12 @@ const openmlSection = [ title: "sidebar.benchmarks", children: [ { - href: "/benchmarks/tasks", + href: "/benchmarks/tasks/search", title: "sidebar.task_suites", badge: "100", }, { - href: "/benchmarks/runs", + href: "/benchmarks/runs/search", title: "sidebar.run_studies", badge: "100", }, @@ -56,17 +56,17 @@ const openmlSection = [ title: "sidebar.measures", children: [ { - href: "/measures/data", + href: "/measures/data/search", title: "sidebar.data_qualities", badge: "100", }, { - href: "/measures/evaluation", + href: "/measures/evaluation/search", title: "sidebar.model_evaluations", badge: "100", }, { - href: "/measures/procedures", + href: "/measures/procedures/search", title: "sidebar.test_procedures", badge: "100", }, diff --git a/app/src/pages/collections/runs.js b/app/src/pages/collections/runs.js index 89cf8484..4b2d60a7 100644 --- a/app/src/pages/collections/runs.js +++ b/app/src/pages/collections/runs.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -18,21 +15,19 @@ export async function getStaticProps({ locale }) { }; } -function DatasetList() { +function RunCollectionList() { return ( - + Run collections - - ); } -DatasetList.getLayout = function getLayout(page) { +RunCollectionList.getLayout = function getLayout(page) { return {page}; }; -export default DatasetList; +export default RunCollectionList; diff --git a/app/src/pages/collections/tasks.js b/app/src/pages/collections/tasks.js index c844493b..f65bb8da 100644 --- a/app/src/pages/collections/tasks.js +++ b/app/src/pages/collections/tasks.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -18,21 +15,19 @@ export async function getStaticProps({ locale }) { }; } -function DatasetList() { +function TaskCollectionList() { return ( - + Task collections - - ); } -DatasetList.getLayout = function getLayout(page) { +TaskCollectionList.getLayout = function getLayout(page) { return {page}; }; -export default DatasetList; +export default TaskCollectionList; diff --git a/app/src/pages/d/index.js b/app/src/pages/d/index.js index b67ebb27..5708dcb6 100644 --- a/app/src/pages/d/index.js +++ b/app/src/pages/d/index.js @@ -16,7 +16,7 @@ export async function getStaticProps({ locale }) { }; } -function Dataset() { +function DatasetList() { return ( @@ -27,8 +27,8 @@ function Dataset() { ); } -Dataset.getLayout = function getLayout(page) { +DatasetList.getLayout = function getLayout(page) { return {page}; }; -export default Dataset; +export default DatasetList; diff --git a/app/src/pages/d/search.js b/app/src/pages/d/search.js index 96925d8a..d379c307 100644 --- a/app/src/pages/d/search.js +++ b/app/src/pages/d/search.js @@ -7,6 +7,10 @@ import { renderCell, valueGetter, copyCell, + renderDescription, + renderDate, + renderTags, + renderChips, } from "../../components/search/ResultTable"; import Chip from "@mui/material/Chip"; @@ -15,11 +19,9 @@ import { faCheck, faTriangleExclamation, faRotate, - faEllipsis, } from "@fortawesome/free-solid-svg-icons"; import searchConfig from "./searchConfig"; -import TimeAgo from "react-timeago"; import { faCreativeCommonsBy, faCreativeCommonsPd, @@ -28,7 +30,6 @@ import { // Server-side translation import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import Teaser from "../../components/search/Teaser"; export async function getStaticProps(context) { // extract the locale identifier from the URL const { locale } = context; @@ -40,6 +41,7 @@ export async function getStaticProps(context) { }; } +// Defines chips in table view const getChipProps = (value) => { switch (value) { // Dataset status @@ -102,79 +104,6 @@ const getChipProps = (value) => { } }; -const renderChips = (params) => { - const { label, icon, color } = getChipProps(params.value); - return ( -
- -
- ); -}; - -const renderTags = (params) => { - const { value } = params; - - // Return nothing if the label is empty - if (!value) { - return null; - } - - // Split the label by commas to create an array of tags - const labels = value - .split(",") - .map((label) => label.trim()) - .filter((label) => label); - - // Determine if there are more than 3 labels - const hasMore = labels.length > 3; - - // Slice the array to the first 3 labels if there are more than 3 - const visibleLabels = hasMore ? labels.slice(0, 3) : labels; - - // Map each tag to a Chip component and add a margin for spacing - const chips = visibleLabels.map((label, index) => ( - - )); - - return ( -
- {chips} - {hasMore && ( - } - size="small" - variant="outlined" - sx={{ paddingLeft: "8px" }} // Match the margin of other chips - /> - )} -
- ); -}; - -const renderDate = (params) => { - return ; -}; - -const renderDescription = (params) => { - return ( -
- -
- ); -}; - const sort_options = [ { name: "search.relevance", @@ -261,7 +190,7 @@ const columns = [ field: "status", headerName: "Status", valueGetter: valueGetter("status"), - renderCell: renderChips, + renderCell: renderChips(getChipProps), type: "singleSelect", valueOptions: ["active", "deactivated", "in_preparation"], width: 136, @@ -283,7 +212,7 @@ const columns = [ field: "licence", headerName: "Licence", valueGetter: valueGetter("licence"), - renderCell: renderChips, + renderCell: renderChips(getChipProps), width: 110, }, { diff --git a/app/src/pages/f/[flowId].js b/app/src/pages/f/[flowId].js new file mode 100644 index 00000000..8fa93388 --- /dev/null +++ b/app/src/pages/f/[flowId].js @@ -0,0 +1,42 @@ +import { useRouter } from "next/router"; +import React from "react"; +import { Helmet } from "react-helmet-async"; +import { Typography } from "@mui/material"; +import DashboardLayout from "../../layouts/Dashboard"; + +// Server-side translation +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; + +export async function getStaticPaths() { + // No paths are pre-rendered + return { paths: [], fallback: "blocking" }; // or fallback: true, if you prefer +} + +export async function getStaticProps({ params, locale }) { + // Fetch necessary data for the dataset page using params.dataId + return { + props: { + // pass the translation props to the page component + ...(await serverSideTranslations(locale)), + }, + }; +} + +function Flow() { + const router = useRouter(); + const flowId = router.query.flowId; + return ( + + + + Flow {flowId} + + + ); +} + +Flow.getLayout = function getLayout(page) { + return {page}; +}; + +export default Flow; diff --git a/app/src/pages/f/index.js b/app/src/pages/f/index.js index 495531d2..6a7edc74 100644 --- a/app/src/pages/f/index.js +++ b/app/src/pages/f/index.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -25,8 +22,6 @@ function FlowList() { Flows - -
); } diff --git a/app/src/pages/measures/data.js b/app/src/pages/measures/data.js index c472f747..8b7f7d37 100644 --- a/app/src/pages/measures/data.js +++ b/app/src/pages/measures/data.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -18,21 +15,19 @@ export async function getStaticProps({ locale }) { }; } -function DatasetList() { +function DataMeasureList() { return ( Data qualities - - ); } -DatasetList.getLayout = function getLayout(page) { +DataMeasureList.getLayout = function getLayout(page) { return {page}; }; -export default DatasetList; +export default DataMeasureList; diff --git a/app/src/pages/measures/evaluation.js b/app/src/pages/measures/evaluation.js index ab165f5c..57a229c7 100644 --- a/app/src/pages/measures/evaluation.js +++ b/app/src/pages/measures/evaluation.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -18,21 +15,19 @@ export async function getStaticProps({ locale }) { }; } -function DatasetList() { +function EvaluationMetricList() { return ( Model evaluations - - ); } -DatasetList.getLayout = function getLayout(page) { +EvaluationMetricList.getLayout = function getLayout(page) { return {page}; }; -export default DatasetList; +export default EvaluationMetricList; diff --git a/app/src/pages/measures/procedures.js b/app/src/pages/measures/procedures.js index a316b4a7..fdd5cf5c 100644 --- a/app/src/pages/measures/procedures.js +++ b/app/src/pages/measures/procedures.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -18,21 +15,19 @@ export async function getStaticProps({ locale }) { }; } -function DatasetList() { +function EvaluationProcedureList() { return ( Test procedures - - ); } -DatasetList.getLayout = function getLayout(page) { +EvaluationProcedureList.getLayout = function getLayout(page) { return {page}; }; -export default DatasetList; +export default EvaluationProcedureList; diff --git a/app/src/pages/u/index.js b/app/src/pages/r/[runId].js similarity index 53% rename from app/src/pages/u/index.js rename to app/src/pages/r/[runId].js index 0160301e..bffb3644 100644 --- a/app/src/pages/u/index.js +++ b/app/src/pages/r/[runId].js @@ -1,38 +1,42 @@ -import React from "react"; -import { Helmet } from "react-helmet-async"; - -import { Typography } from "@mui/material"; - -import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; - -// Server-side translation -import { useTranslation } from "next-i18next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -export async function getStaticProps({ locale }) { - return { - props: { - // pass the translation props to the page component - ...(await serverSideTranslations(locale)), - }, - }; -} - -function UserList() { - return ( - - - - Users - - - - - ); -} - -UserList.getLayout = function getLayout(page) { - return {page}; -}; - -export default UserList; +import { useRouter } from "next/router"; +import React from "react"; +import { Helmet } from "react-helmet-async"; +import { Typography } from "@mui/material"; +import DashboardLayout from "../../layouts/Dashboard"; + +// Server-side translation +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; + +export async function getStaticPaths() { + // No paths are pre-rendered + return { paths: [], fallback: "blocking" }; // or fallback: true, if you prefer +} + +export async function getStaticProps({ params, locale }) { + // Fetch necessary data for the dataset page using params.dataId + return { + props: { + // pass the translation props to the page component + ...(await serverSideTranslations(locale)), + }, + }; +} + +function Run() { + const router = useRouter(); + const runId = router.query.runId; + return ( + + + + Run {runId} + + + ); +} + +Run.getLayout = function getLayout(page) { + return {page}; +}; + +export default Run; diff --git a/app/src/pages/r/index.js b/app/src/pages/r/index.js index f79c624c..e099dc75 100644 --- a/app/src/pages/r/index.js +++ b/app/src/pages/r/index.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -25,8 +22,6 @@ function RunList() { Runs - - ); } diff --git a/app/src/pages/t/[taskId].js b/app/src/pages/t/[taskId].js new file mode 100644 index 00000000..14096a32 --- /dev/null +++ b/app/src/pages/t/[taskId].js @@ -0,0 +1,42 @@ +import { useRouter } from "next/router"; +import React from "react"; +import { Helmet } from "react-helmet-async"; +import { Typography } from "@mui/material"; +import DashboardLayout from "../../layouts/Dashboard"; + +// Server-side translation +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; + +export async function getStaticPaths() { + // No paths are pre-rendered + return { paths: [], fallback: "blocking" }; // or fallback: true, if you prefer +} + +export async function getStaticProps({ params, locale }) { + // Fetch necessary data for the dataset page using params.dataId + return { + props: { + // pass the translation props to the page component + ...(await serverSideTranslations(locale)), + }, + }; +} + +function Task() { + const router = useRouter(); + const taskId = router.query.taskId; + return ( + + + + Task {taskId} + + + ); +} + +Task.getLayout = function getLayout(page) { + return {page}; +}; + +export default Task; diff --git a/app/src/pages/t/index.js b/app/src/pages/t/index.js index 3c312f06..a643ae40 100644 --- a/app/src/pages/t/index.js +++ b/app/src/pages/t/index.js @@ -1,10 +1,7 @@ import React from "react"; import { Helmet } from "react-helmet-async"; - import { Typography } from "@mui/material"; - import DashboardLayout from "../../layouts/Dashboard"; -import TableView from "../../components/TableView"; // Server-side translation import { useTranslation } from "next-i18next"; @@ -23,10 +20,8 @@ function TaskList() { - Tasks + Task overview - - ); } diff --git a/app/src/pages/t/search.js b/app/src/pages/t/search.js new file mode 100644 index 00000000..765f7fb7 --- /dev/null +++ b/app/src/pages/t/search.js @@ -0,0 +1,73 @@ +import React from "react"; +import { useNextRouting } from "../../utils/useNextRouting"; + +import DashboardLayout from "../../layouts/Dashboard"; +import SearchContainer from "../../components/search/SearchContainer"; +import { renderCell, valueGetter } from "../../components/search/ResultTable"; + +import searchConfig from "./searchConfig"; + +// Server-side translation +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +export async function getStaticProps(context) { + // extract the locale identifier from the URL + const { locale } = context; + return { + props: { + // pass the translation props to the page component + ...(await serverSideTranslations(locale)), + }, + }; +} + +const sort_options = [ + { + name: "search.relevance", + value: [], + }, + { + name: "search.most_recent", + value: [{ field: "date", direction: "desc" }], + }, +]; + +const search_facets = [ + { + label: "filters.status", + field: "status.keyword", + }, +]; + +// Controls how columns are rendered and manipulated in the table view +const columns = [ + { + field: "task_id", + headerName: "Task_id", + valueGetter: valueGetter("task_id"), + renderCell: renderCell, + width: 70, + }, +]; + +function TaskSearchContainer() { + const combinedConfig = useNextRouting(searchConfig, ""); + + return ( + + ); +} + +TaskSearchContainer.getLayout = function getLayout(page) { + return {page}; +}; + +TaskSearchContainer.displayName = "TaskSearchContainer"; + +export default TaskSearchContainer; diff --git a/app/src/pages/t/searchConfig.js b/app/src/pages/t/searchConfig.js new file mode 100644 index 00000000..2cf0f516 --- /dev/null +++ b/app/src/pages/t/searchConfig.js @@ -0,0 +1,40 @@ +import Connector from "../../services/SearchAPIConnector"; +const apiConnector = new Connector("task"); + +const searchConfig = { + apiConnector: apiConnector, + alwaysSearchOnInitialLoad: true, + searchQuery: { + resultsPerPage: 100, + search_fields: { + description: {}, + }, + result_fields: { + creator: { raw: {} }, + task_id: { raw: {} }, + date: { raw: {} }, + }, + disjunctiveFacets: [], + facets: {}, + group: { + //This doesn't work yet. TODO: figure out how to group. + field: { name: { raw: {} } }, + }, + }, + autocompleteQuery: { + results: { + resultsPerPage: 100, + result_fields: { + // specify the fields you want from the index to display the results + name: { snippet: { size: 100, fallback: true } }, + url: { raw: {} }, + }, + search_fields: { + // specify the fields you want to search on + name: {}, + }, + }, + }, +}; + +export default searchConfig; diff --git a/app/src/pages/u/[userId].js b/app/src/pages/u/[userId].js deleted file mode 100644 index 66f2fa00..00000000 --- a/app/src/pages/u/[userId].js +++ /dev/null @@ -1,26 +0,0 @@ -import { useRouter } from "next/router"; -import React from "react"; -import { Helmet } from "react-helmet-async"; - -import { Typography } from "@mui/material"; - -import DashboardLayout from "../../layouts/Dashboard"; - -function User() { - const router = useRouter(); - const userId = router.query.userId; - return ( - - - - User {userId} - - - ); -} - -User.getLayout = function getLayout(page) { - return {page}; -}; - -export default User;