From 4f5e97171865064c4d85f5f2da7d568788d4dae0 Mon Sep 17 00:00:00 2001 From: Alex Tilot <34109200+Nezzely@users.noreply.github.com> Date: Fri, 3 Mar 2023 15:27:50 -0600 Subject: [PATCH] feat: topic criteria table transposes rows & columns * feat: topic criteria table transposes rows & columns * chore: feeling emo, might delete --- .../CriteriaTable/CriteriaTable.styles.tsx | 16 ++-- .../CriteriaTable/CriteriaTable.tsx | 74 ++++++++++--------- web/src/modules/topic/utils/edge.ts | 11 +++ 3 files changed, 62 insertions(+), 39 deletions(-) diff --git a/web/src/modules/topic/components/CriteriaTable/CriteriaTable.styles.tsx b/web/src/modules/topic/components/CriteriaTable/CriteriaTable.styles.tsx index 057409f8..55570ad5 100644 --- a/web/src/modules/topic/components/CriteriaTable/CriteriaTable.styles.tsx +++ b/web/src/modules/topic/components/CriteriaTable/CriteriaTable.styles.tsx @@ -1,6 +1,6 @@ import { css } from "@emotion/react"; import styled from "@emotion/styled"; -import { IconButton } from "@mui/material"; +import { Button, IconButton } from "@mui/material"; import { AddNodeButton } from "../AddNodeButton/AddNodeButton"; import { nodeWidth } from "../EditableNode/EditableNode.styles"; @@ -60,12 +60,11 @@ const tableDivOptions = { }; export const TableDiv = styled("div", tableDivOptions)` + left: 50%; + transform: translateX(-50%); + position: relative; ${({ numberOfColumns }) => { return css` - left: 50%; - transform: translateX(-50%); - position: relative; - // Want to have table grow with columns, so we hardcode a total-width of table, but, if column widths // are hardcoded as well, doing so will create a horizontal scrollbar whenever too many rows results in a vertical scrollbar. // Therefore, the total-width will have a little extra space so that nodes are still >= min-width @@ -85,7 +84,6 @@ const options = { export const PositionedAddNodeButton = styled(AddNodeButton, options)` position: absolute; - ${({ position }) => { if (position === "column") { return css` @@ -102,3 +100,9 @@ export const PositionedAddNodeButton = styled(AddNodeButton, options) { - const edge = edges.find((edge) => edge.source === criterion.id && edge.target === solution.id); - if (!edge) throw new Error(`No edge found between ${criterion.id} and ${solution.id}`); - - return edge; -}; - type RowData = Record; // returns structure: @@ -33,38 +29,37 @@ type RowData = Record; // [solution_id: string]: Edge, // } // but not sure how to type this because index signatures require _all_ properties to match the specified type -const buildRows = ( - criteria: Node[], - solutions: Node[], - criterionSolutionEdges: Edge[] -): RowData[] => { - return criteria.map((criterion) => { + +const buildRows = (rowNodes: Node[], columnNodes: Node[], edges: Edge[]): RowData[] => { + return rowNodes.map((rowNode) => { return { - criterion, + rowNode, ...Object.fromEntries( - solutions.map((solution) => [ - solution.id, - getCriterionSolutionEdge(criterion, solution, criterionSolutionEdges), + columnNodes.map((columnNode) => [ + columnNode.id, + getConnectingEdge(rowNode, columnNode, edges), ]) ), }; }); }; -const buildColumns = (solutions: Node[]): MRT_ColumnDef[] => { +const buildColumns = (columnNodes: Node[]): MRT_ColumnDef[] => { return [ { - accessorKey: "criterion.data.label", // this determines how cols should sort/filter + accessorKey: "rowNode.data.label", // this determines how cols should sort/filter header: "", // corner column header, and solutions are along the top - Cell: ({ row }) => , + Cell: ({ row }) => { + return ; + }, }, - ...solutions.map( - (solution) => + ...columnNodes.map( + (columnNode) => ({ - accessorKey: `${solution.id}.data.score`, // we'll sort/filter edges by their score for now I guess + accessorKey: `${columnNode.id}.data.score`, // we'll sort/filter edges by their score for now I guess header: "Score", - Header: , - Cell: ({ row }) => , + Header: , + Cell: ({ row }) => , } as MRT_ColumnDef) ), ]; @@ -75,6 +70,7 @@ interface Props { } export const CriteriaTable = ({ problemNodeId }: Props) => { + const [useSolutionsForColumns, setUseSolutionsForColumns] = useState(true); const problemNode = useNode(problemNodeId, problemDiagramId); const nodeChildren = useNodeChildren(problemNodeId, problemDiagramId); const criterionSolutionEdges = useCriterionSolutionEdges(problemNodeId, problemDiagramId); @@ -84,8 +80,11 @@ export const CriteriaTable = ({ problemNodeId }: Props) => { const criteria = nodeChildren.filter((node) => node.type === "criterion"); const solutions = nodeChildren.filter((node) => node.type === "solution"); - const rowData = buildRows(criteria, solutions, criterionSolutionEdges); - const columns = buildColumns(solutions); + const rowNodes = useSolutionsForColumns ? criteria : solutions; + const columnNodes = useSolutionsForColumns ? solutions : criteria; + + const rowData = buildRows(rowNodes, columnNodes, criterionSolutionEdges); + const columnData = buildColumns(columnNodes); return ( <> @@ -98,11 +97,11 @@ export const CriteriaTable = ({ problemNodeId }: Props) => { - + {/* Hard to tell if material-react-table is worth using because the cells are all custom components. */} {/* It's doubtful that we'll use sorting/filtering... but pinning and re-ordering may come in handy. */} { muiTablePaperProps={{ className: "criteria-table-paper", }} - initialState={{ columnPinning: { left: ["criterion.data.label"] } }} + initialState={{ columnPinning: { left: ["rowNode.data.label"] } }} /> + setUseSolutionsForColumns(!useSolutionsForColumns)} + > + + + { /> { export const childNode = (edge: Edge, diagram: Diagram) => { return findScorable(diagram, edge.target, "node"); }; + +export const getConnectingEdge = (node1: Node, node2: Node, edges: Edge[]) => { + const edge = edges.find( + (edge) => + (edge.source === node1.id && edge.target === node2.id) || + (edge.source === node2.id && edge.target === node1.id) + ); + if (!edge) throw new Error(`No edge found between ${node1.id} and ${node2.id}`); + + return edge; +};