From b112969d87a82016c7d960715c6f2fb457ce199f Mon Sep 17 00:00:00 2001 From: Luis-Hebendanz Date: Mon, 14 Aug 2023 15:56:31 +0200 Subject: [PATCH 1/4] Fixed mobile layout in Pie Chart and in table --- pkgs/ui/src/app/nodes/NodeList.tsx | 21 +++++++++++++-------- pkgs/ui/src/app/nodes/NodePieChart.tsx | 14 ++++++++++++++ pkgs/ui/src/app/nodes/page.tsx | 9 +++------ 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/pkgs/ui/src/app/nodes/NodeList.tsx b/pkgs/ui/src/app/nodes/NodeList.tsx index f00dee905..98ce5e182 100644 --- a/pkgs/ui/src/app/nodes/NodeList.tsx +++ b/pkgs/ui/src/app/nodes/NodeList.tsx @@ -194,9 +194,9 @@ function EnhancedTableToolbar(props: EnhancedTableToolbarProps) { ).length; return [ - { name: "Online", value: online, color: "#2E7D32" }, - { name: "Offline", value: offline, color: "#db3927" }, - { name: "Pending", value: pending, color: "#FFBB28" }, + { name: "Online", value: online, color: theme.palette.success.main }, + { name: "Offline", value: offline, color: theme.palette.error.main }, + { name: "Pending", value: pending, color: theme.palette.warning.main }, ]; }, [tableData]); @@ -230,7 +230,7 @@ function EnhancedTableToolbar(props: EnhancedTableToolbarProps) { height: 110, backgroundColor: hexRgb(pieItem.color, { format: "css", - alpha: 0.18, + alpha: 0.25, }), }} > @@ -338,7 +338,7 @@ function EnhancedTableToolbar(props: EnhancedTableToolbarProps) { {cardStack} @@ -426,6 +426,10 @@ export interface NodeTableProps { export default function NodeTable(props: NodeTableProps) { let { tableData } = props; + + const theme = useTheme(); + const is_xs = useMediaQuery(theme.breakpoints.only("xs")); + const [order, setOrder] = React.useState("asc"); const [orderBy, setOrderBy] = React.useState("status"); const [selected, setSelected] = React.useState(undefined); @@ -479,7 +483,7 @@ export default function NodeTable(props: NodeTableProps) { ); return ( - + - + ); } diff --git a/pkgs/ui/src/app/nodes/NodePieChart.tsx b/pkgs/ui/src/app/nodes/NodePieChart.tsx index 12ed80418..cc28e01ee 100644 --- a/pkgs/ui/src/app/nodes/NodePieChart.tsx +++ b/pkgs/ui/src/app/nodes/NodePieChart.tsx @@ -37,6 +37,20 @@ export default function NodePieChart(props: Props) { dataKey="value" nameKey="name" label={showLabels} + legendType="circle" + cx="50%" + cy="50%" + startAngle={0} + endAngle={360} + paddingAngle={0} + labelLine={true} + hide={false} + minAngle={0} + isAnimationActive={true} + animationBegin={0} + animationDuration={1000} + animationEasing="ease-in" + blendStroke={true} > {data.map((entry, index) => ( diff --git a/pkgs/ui/src/app/nodes/page.tsx b/pkgs/ui/src/app/nodes/page.tsx index 3e4190ba9..b269e9773 100644 --- a/pkgs/ui/src/app/nodes/page.tsx +++ b/pkgs/ui/src/app/nodes/page.tsx @@ -4,15 +4,12 @@ import NodeList from "./NodeList"; import Box from "@mui/material/Box"; import { tableData } from "@/data/nodeData"; +import { StrictMode } from "react"; export default function Page() { return ( - + - + ); } From 3489ebc5c4909ba662166602ac5122cf8c43e47a Mon Sep 17 00:00:00 2001 From: Luis-Hebendanz Date: Mon, 14 Aug 2023 18:25:06 +0200 Subject: [PATCH 2/4] Added collapse to table --- pkgs/ui/src/app/nodes/NodeList.tsx | 427 ++++++++++++++++------------- pkgs/ui/src/app/theme/themes.ts | 18 ++ 2 files changed, 258 insertions(+), 187 deletions(-) diff --git a/pkgs/ui/src/app/nodes/NodeList.tsx b/pkgs/ui/src/app/nodes/NodeList.tsx index 98ce5e182..2228e7b19 100644 --- a/pkgs/ui/src/app/nodes/NodeList.tsx +++ b/pkgs/ui/src/app/nodes/NodeList.tsx @@ -27,11 +27,14 @@ import Stack from "@mui/material/Stack/Stack"; import ModeIcon from "@mui/icons-material/Mode"; import ClearIcon from "@mui/icons-material/Clear"; import Fade from "@mui/material/Fade/Fade"; +import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; +import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; import NodePieChart, { PieData } from "./NodePieChart"; import Grid2 from "@mui/material/Unstable_Grid2"; // Grid version 2 import { Card, CardContent, + Collapse, Container, FormGroup, useTheme, @@ -111,52 +114,6 @@ function stableSort( return stabilizedThis.map((el) => el[0]); } -interface EnhancedTableProps { - onRequestSort: ( - event: React.MouseEvent, - property: keyof TableData, - ) => void; - order: Order; - orderBy: string; - rowCount: number; -} - -function EnhancedTableHead(props: EnhancedTableProps) { - const { order, orderBy, onRequestSort } = props; - const createSortHandler = - (property: keyof TableData) => (event: React.MouseEvent) => { - onRequestSort(event, property); - }; - - return ( - - - {headCells.map((headCell) => ( - - - {headCell.label} - {orderBy === headCell.id ? ( - - {order === "desc" ? "sorted descending" : "sorted ascending"} - - ) : null} - - - ))} - - - ); -} - interface EnhancedTableToolbarProps { selected: string | undefined; tableData: TableData[]; @@ -337,7 +294,7 @@ function EnhancedTableToolbar(props: EnhancedTableToolbarProps) { {/* Pie Chart Grid */} {cardStack} @@ -366,64 +323,189 @@ function EnhancedTableToolbar(props: EnhancedTableToolbarProps) { ); } -function renderLastSeen(last_seen: number) { - return ( - - {last_seen} days ago - - ); -} - -function renderName(name: string, id: string) { - return ( - - - {name} - - - {id} - - - ); -} - -function renderStatus(status: NodeStatus) { - switch (status) { - case NodeStatus.Online: - return ( - - - - Online - - - ); - - case NodeStatus.Offline: - return ( - - - - Offline - - - ); - case NodeStatus.Pending: - return ( - - - - Pending - - - ); - } -} - export interface NodeTableProps { tableData: TableData[]; } +interface EnhancedTableProps { + onRequestSort: ( + event: React.MouseEvent, + property: keyof TableData, + ) => void; + order: Order; + orderBy: string; + rowCount: number; +} + +function EnhancedTableHead(props: EnhancedTableProps) { + const { order, orderBy, onRequestSort } = props; + const createSortHandler = + (property: keyof TableData) => (event: React.MouseEvent) => { + onRequestSort(event, property); + }; + + return ( + + + + {headCells.map((headCell) => ( + + + {headCell.label} + {orderBy === headCell.id ? ( + + {order === "desc" ? "sorted descending" : "sorted ascending"} + + ) : null} + + + ))} + + + ); +} + +function Row(props: { + row: TableData; + selected: string | undefined; + setSelected: (a: string | undefined) => void; +}) { + function renderStatus(status: NodeStatus) { + switch (status) { + case NodeStatus.Online: + return ( + + + + Online + + + ); + + case NodeStatus.Offline: + return ( + + + + Offline + + + ); + case NodeStatus.Pending: + return ( + + + + Pending + + + ); + } + } + + const { row, selected, setSelected } = props; + const [open, setOpen] = React.useState(false); + //const labelId = `enhanced-table-checkbox-${index}`; + + // Speed optimization. We compare string pointers here instead of the string content. + const isSelected = selected == row.name; + + const handleClick = (event: React.MouseEvent, name: string) => { + if (isSelected) { + setSelected(undefined); + } else { + setSelected(name); + } + }; + + return ( + + + {/* Rendered Row */} + + + setOpen(!open)} + > + {open ? : } + + + handleClick(event, row.name)}> + + + {row.name} + + + {row.id} + + + + handleClick(event, row.name)}>{renderStatus(row.status)} + handleClick(event, row.name)}> + + {row.last_seen} days ago + + + + + {/* Row Expansion */} + + + + + + History + + + + + Date + Customer + Amount + Total price ($) + + + + + Test1 + Test2 + Test + Test + + +
+
+
+
+
+
+ ); +} + export default function NodeTable(props: NodeTableProps) { let { tableData } = props; @@ -446,15 +528,6 @@ export default function NodeTable(props: NodeTableProps) { setOrderBy(property); }; - const handleClick = (event: React.MouseEvent, name: string) => { - // Speed optimization. We compare string pointers here instead of the string content. - if (selected == name) { - setSelected(undefined); - } else { - setSelected(name); - } - }; - const handleChangePage = (event: unknown, newPage: number) => { setPage(newPage); }; @@ -466,9 +539,6 @@ export default function NodeTable(props: NodeTableProps) { setPage(0); }; - // Speed optimization. We compare string pointers here instead of the string content. - const isSelected = (name: string) => name == selected; - // Avoid a layout jump when reaching the last page with empty rows. const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - tableData.length) : 0; @@ -483,79 +553,62 @@ export default function NodeTable(props: NodeTableProps) { ); return ( + + + setSelected(undefined)} + /> + + + + + {visibleRows.map((row, index) => { + const labelId = `enhanced-table-checkbox-${index}`; - - - setSelected(undefined)} - /> - -
- - - {visibleRows.map((row, index) => { - const isItemSelected = isSelected(row.name); - const labelId = `enhanced-table-checkbox-${index}`; - - return ( - handleClick(event, row.name)} - role="checkbox" - aria-checked={isItemSelected} - tabIndex={-1} - key={row.name} - selected={isItemSelected} - sx={{ cursor: "pointer" }} - > - - {renderName(row.name, row.id)} - - - {renderStatus(row.status)} - - - {renderLastSeen(row.last_seen)} - - - ); - })} - {emptyRows > 0 && ( - - - - )} - -
-
- {/* TODO: This creates the error Warning: Prop `id` did not match. Server: ":RspmmcqH1:" Client: ":R3j6qpj9H1:" */} - -
-
- + return ( + + ); + })} + {emptyRows > 0 && ( + + + + )} + + + + {/* TODO: This creates the error Warning: Prop `id` did not match. Server: ":RspmmcqH1:" Client: ":R3j6qpj9H1:" */} + + + ); } diff --git a/pkgs/ui/src/app/theme/themes.ts b/pkgs/ui/src/app/theme/themes.ts index fd845dec0..edd2786ee 100644 --- a/pkgs/ui/src/app/theme/themes.ts +++ b/pkgs/ui/src/app/theme/themes.ts @@ -1,12 +1,30 @@ import { createTheme } from "@mui/material/styles"; export const darkTheme = createTheme({ + breakpoints: { + values: { + xs: 0, + sm: 400, + md: 900, + lg: 1200, + xl: 1536, + }, + }, palette: { mode: "dark", }, }); export const lightTheme = createTheme({ + breakpoints: { + values: { + xs: 0, + sm: 400, + md: 900, + lg: 1200, + xl: 1536, + }, + }, palette: { mode: "light", }, From c020cce56b8f80796c43490c6d4965e17dc0f83f Mon Sep 17 00:00:00 2001 From: Luis-Hebendanz Date: Mon, 14 Aug 2023 19:08:15 +0200 Subject: [PATCH 3/4] UI: Replaced enum infavor of hash keys --- pkgs/ui/src/app/layout.tsx | 14 ++++++++++++++ pkgs/ui/src/app/nodes/NodeList.tsx | 4 ++-- pkgs/ui/src/data/nodeData.tsx | 14 ++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pkgs/ui/src/app/layout.tsx b/pkgs/ui/src/app/layout.tsx index 208d3e8d5..804349216 100644 --- a/pkgs/ui/src/app/layout.tsx +++ b/pkgs/ui/src/app/layout.tsx @@ -8,6 +8,7 @@ import { IconButton, ThemeProvider, useMediaQuery, + useTheme, } from "@mui/material"; import { ChangeEvent, useState } from "react"; @@ -38,8 +39,21 @@ export default function RootLayout({ children: React.ReactNode; }) { const userPrefersDarkmode = useMediaQuery("(prefers-color-scheme: dark)"); + const theme = useTheme(); + const is_small = useMediaQuery(theme.breakpoints.down("sm")); + let [useDarkTheme, setUseDarkTheme] = useState(false); let [showSidebar, setShowSidebar] = useState(true); + + // If the screen is small, hide the sidebar + React.useEffect(() => { + if (is_small) { + setShowSidebar(false); + } else { + setShowSidebar(true); + } + }, [is_small]); + React.useEffect(() => { if (useDarkTheme !== userPrefersDarkmode) { // Enable dark theme if the user prefers dark mode diff --git a/pkgs/ui/src/app/nodes/NodeList.tsx b/pkgs/ui/src/app/nodes/NodeList.tsx index 2228e7b19..b0bac51a7 100644 --- a/pkgs/ui/src/app/nodes/NodeList.tsx +++ b/pkgs/ui/src/app/nodes/NodeList.tsx @@ -41,7 +41,7 @@ import { } from "@mui/material"; import hexRgb from "hex-rgb"; import useMediaQuery from "@mui/material/useMediaQuery"; -import { NodeStatus, TableData } from "@/data/nodeData"; +import { NodeStatus, NodeStatusKeys, TableData } from "@/data/nodeData"; interface HeadCell { disablePadding: boolean; @@ -379,7 +379,7 @@ function Row(props: { selected: string | undefined; setSelected: (a: string | undefined) => void; }) { - function renderStatus(status: NodeStatus) { + function renderStatus(status: NodeStatusKeys) { switch (status) { case NodeStatus.Online: return ( diff --git a/pkgs/ui/src/data/nodeData.tsx b/pkgs/ui/src/data/nodeData.tsx index ed15e1e8c..9a73d03f5 100644 --- a/pkgs/ui/src/data/nodeData.tsx +++ b/pkgs/ui/src/data/nodeData.tsx @@ -1,20 +1,22 @@ export interface TableData { name: string; id: string; - status: NodeStatus; + status: NodeStatusKeys; last_seen: number; } -export enum NodeStatus { - Online, - Offline, - Pending, +export const NodeStatus = { + Online: "Online", + Offline: "Offline", + Pending: "Pending", } +export type NodeStatusKeys = typeof NodeStatus[keyof typeof NodeStatus]; + function createData( name: string, id: string, - status: NodeStatus, + status: NodeStatusKeys, last_seen: number, ): TableData { return { From 257e6c1d8e20926036d85a39cfb0dbe2fe2501ee Mon Sep 17 00:00:00 2001 From: Luis-Hebendanz Date: Mon, 14 Aug 2023 19:39:26 +0200 Subject: [PATCH 4/4] UI: Added Metadata view with Grids to List for mobile --- pkgs/ui/src/app/nodes/NodeList.tsx | 67 ++++++++++++++++---------- pkgs/ui/src/app/nodes/NodePieChart.tsx | 2 +- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/pkgs/ui/src/app/nodes/NodeList.tsx b/pkgs/ui/src/app/nodes/NodeList.tsx index b0bac51a7..2784a2d39 100644 --- a/pkgs/ui/src/app/nodes/NodeList.tsx +++ b/pkgs/ui/src/app/nodes/NodeList.tsx @@ -347,7 +347,7 @@ function EnhancedTableHead(props: EnhancedTableProps) { return ( - + {headCells.map((headCell) => ( div": { + borderRight: "var(--Grid-borderWidth) solid", + borderBottom: "var(--Grid-borderWidth) solid", + borderColor: "divider", + }, + } + : {}; + return ( - {/* Rendered Row */} - + : } - handleClick(event, row.name)}> + handleClick(event, row.name)} + > {row.name} @@ -464,8 +482,16 @@ function Row(props: { - handleClick(event, row.name)}>{renderStatus(row.status)} - handleClick(event, row.name)}> + handleClick(event, row.name)} + > + {renderStatus(row.status)} + + handleClick(event, row.name)} + > {row.last_seen} days ago @@ -478,26 +504,17 @@ function Row(props: { - History + Metadata - - - - Date - Customer - Amount - Total price ($) - - - - - Test1 - Test2 - Test - Test - - -
+ + + Hello1 + + + Hello2 + + +
diff --git a/pkgs/ui/src/app/nodes/NodePieChart.tsx b/pkgs/ui/src/app/nodes/NodePieChart.tsx index cc28e01ee..e076656cc 100644 --- a/pkgs/ui/src/app/nodes/NodePieChart.tsx +++ b/pkgs/ui/src/app/nodes/NodePieChart.tsx @@ -37,7 +37,7 @@ export default function NodePieChart(props: Props) { dataKey="value" nameKey="name" label={showLabels} - legendType="circle" + legendType="square" cx="50%" cy="50%" startAngle={0}