diff --git a/indexV2.html b/indexV2.html
new file mode 100644
index 0000000..31b4ca1
--- /dev/null
+++ b/indexV2.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ Adaptive Dashboard
+
+
+
+
+
+
+
diff --git a/nginx.conf b/nginx.conf
index 8e8fc75..adb8457 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -61,7 +61,12 @@ http {
expires $cache_expires;
root /usr/share/nginx/html;
- try_files $uri /index.html;
+ try_files $uri /indexV2.html;
+
+ location = /index.html {
+ return 301 /indexV2.html;
+ }
+
}
# Healthcheck
diff --git a/src/cableEstimator/cableEstimator.tsx b/src/cableEstimator/cableEstimator.tsx
index 17f909c..86a27b7 100644
--- a/src/cableEstimator/cableEstimator.tsx
+++ b/src/cableEstimator/cableEstimator.tsx
@@ -140,7 +140,7 @@ export default function CableEstimator() {
},
{
title: "Peak Height" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
- sortKey: "PeakHeight",
+ sortKey: "Peak",
render: (row: jsonBin) => {distanceConversion(row.Peak).toFixed(2)}
},
{
diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx
index ee1e9dd..f904e0a 100644
--- a/src/common/ResponsiveTable.tsx
+++ b/src/common/ResponsiveTable.tsx
@@ -1,7 +1,7 @@
import { Box, Button, Card, Checkbox, CircularProgress, Collapse, darken, Divider, Grid2, IconButton, InputAdornment, ListItemButton, ListItemIcon, ListItemText, Menu, MenuItem, Paper, SxProps, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Theme, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { ArrowDownward, ArrowUpward, ChevronRight, Close, Search, ViewColumn } from "@mui/icons-material"
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
import React from "react";
import { useMobile } from "hooks";
import classNames from "classnames";
@@ -99,7 +99,8 @@ interface Props {
order?: string;
setOrder?: React.Dispatch>;
endTitleElement?: string | JSX.Element | (() => string | JSX.Element);
- loadMore?: () => void
+ loadMore?: () => void;
+ resizeable?: boolean;
}
export default function ResponsiveTable(props: Props) {
@@ -133,14 +134,15 @@ export default function ResponsiveTable(props: Props) {
setOrderBy,
order,
setOrder,
- loadMore
+ loadMore,
+ // resizeable,
} = props
const classes = useStyles();
const columns = typeof(props.columns) === "function" ? props.columns() : props.columns
const subtitle = typeof(props.subtitle) === "function" ? props.subtitle() : props.subtitle
const title = typeof(props.title) === "function" ? props.title() : props.title
- // const order = props.order ? props.order : "asc"
const endTitleElement = typeof(props.endTitleElement) === "function" ? props.endTitleElement() : props.endTitleElement
+ const resizeable = props.resizeable === undefined ? false : props.resizeable
const isMobile = useMobile()
@@ -148,6 +150,19 @@ export default function ResponsiveTable(props: Props) {
const [openGutters, setOpenGutters] = useState([])
const [handler, setHandler] = useState(undefined);
const [columnAnchor, setColumnAnchor] = useState(null)
+
+ const rowKey = window.location.pathname.split('/').pop() + "-table-row-widths";
+ const [rowWidths, setRowWidths] = useState(() => {
+ const saved = localStorage.getItem(rowKey);
+ return saved ? JSON.parse(saved) : [];
+ })
+ useEffect(() => {
+ localStorage.setItem(rowKey, JSON.stringify(rowWidths));
+ }, [rowWidths])
+
+ const dragIndexRef = useRef(undefined);
+ const dragStartRef = useRef(undefined);
+ const rowWidthsRef = useRef([]);
const filterKey = window.location.pathname.split('/').pop() + "-table-filter-list";
@@ -274,9 +289,7 @@ export default function ResponsiveTable(props: Props) {
}
const renderMobileRow = (row: T, index: number) => {
- if (renderMobile) return (
- renderMobile(row, index)
- )
+ if (renderMobile) return renderMobile(row, index)
if (columns) {
return (
@@ -299,8 +312,7 @@ export default function ResponsiveTable(props: Props) {
}
return (
Object.keys(row).map((key, index) => {
- let value = row[key as keyof typeof row]
-
+ const value = row[key as keyof typeof row]
return (
@@ -346,7 +358,6 @@ export default function ResponsiveTable(props: Props) {
padding: gutterPadding
}}
onClick={(event) => handleCollapse(index, event)}
- // style={{pre}}
>
(props: Props) {
const columnClick = (column: Column) => {
const sortKey = column.sortKey ? column.sortKey : column.title.toLowerCase()
- // console.log(column.sortKey)
if (setOrderBy) {
if (orderBy === sortKey && setOrder && order) {
if (order === "desc") {
@@ -409,13 +419,11 @@ export default function ResponsiveTable(props: Props) {
} else {
setOrderBy("")
}
- // setOrder(order === "asc" ? "desc" : "asc")
} else {
if (setOrder) setOrder("desc")
setOrderBy(sortKey)
}
}
- // if (setOrder && order) setOrder(order === "asc" ? "desc" : "asc")
}
const showOrderIcon = (column: Column) => {
@@ -423,14 +431,60 @@ export default function ResponsiveTable(props: Props) {
const sortKey = column.sortKey ? column.sortKey : column.title.toLowerCase()
if (sortKey === orderBy) {
if (order === "asc") {
- return
+ return
} else {
- return
+ return
}
}
return null;
}
+ const resizeClick = (event: React.MouseEvent, index: number) => {
+
+ let newWidths: number[] = []
+ event.currentTarget.parentElement?.parentElement?.parentElement?.childNodes.forEach(node => {
+ if (node instanceof HTMLElement) {
+ newWidths.push(node.clientWidth)
+ }
+ })
+
+ rowWidthsRef.current = newWidths
+ dragIndexRef.current = index;
+ dragStartRef.current = event.clientX;
+
+ window.addEventListener('mousemove', resizeDrag);
+ window.addEventListener('mouseup', resizeUnclick);
+ }
+
+ const resizeUnclick = () => {
+ dragIndexRef.current = undefined;
+ dragStartRef.current = undefined;
+ window.removeEventListener('mousemove', resizeDrag);
+ window.removeEventListener('mouseup', resizeUnclick);
+ }
+
+ const resizeDrag = (e: any) => {
+ const index = dragIndexRef.current;
+ const dragStart = dragStartRef.current
+ const rowWidths = rowWidthsRef.current
+ if (index === undefined) return
+ if (rowWidths[index] === undefined) return
+ if (rowWidths[index+1] === undefined) return
+ if (!dragStart) return
+
+ let newWidths: number[] = [...rowWidths]
+ newWidths[index] = newWidths[index] - (dragStart - e.clientX)
+ newWidths.every((width, j) => {
+ if (j <= index || width === 0) return true
+ else if (newWidths[j] !== undefined) {
+ newWidths[j] = newWidths[j] + (dragStart - e.clientX)
+ return false
+ }
+ })
+ setRowWidths(newWidths)
+
+ }
+
return (
@@ -483,15 +537,28 @@ export default function ResponsiveTable(props: Props) {
{ renderGutter && }
{ columns ?
columns.map((column, index) => {
- if (filterList.includes(column.title) || column.hidden) return null
+ if (filterList.includes(column.title) || column.hidden) return (
+
+ )
return (
- !column.disableSort && columnClick(column)}
- sx={{ cursor: column.disableSort ? "default" : "pointer" }}
- >
-
- {column.title} {showOrderIcon(column)}
+
+
+ !column.disableSort && columnClick(column)}
+ sx={{ cursor: column.disableSort ? "default" : "pointer" }}
+ >
+ {column.title} {showOrderIcon(column)}
+
+ {index < columns.length-1 && resizeable &&
+ resizeClick(event, index)}
+ >
+ |
+
+ }
)
@@ -547,15 +614,17 @@ export default function ResponsiveTable(props: Props) {
}
{columns ?
columns.map((column, j) => {
- if (filterList.includes(column.title) || column.hidden) return null
+ if (filterList.includes(column.title) || column.hidden) return (
+
+ )
if (column.render) return (
-
+
{column.render(row)}
)
return (
- {Object.values(row)[j].toString()}
+ {Object.values(row)[j] && Object.values(row)[j].toString()}
)
})
@@ -615,9 +684,8 @@ export default function ResponsiveTable(props: Props) {
)
})}
+
)
diff --git a/src/pages/Devices.tsx b/src/pages/Devices.tsx
index 9e8bb0d..8236074 100644
--- a/src/pages/Devices.tsx
+++ b/src/pages/Devices.tsx
@@ -27,6 +27,7 @@ import StatusSen5x from "common/StatusSen5x";
import StatusDust from "common/StatusDust";
import StatusGas from "common/StatusGas";
import { cloneDeep } from "lodash";
+import LoadingScreen from "app/LoadingScreen";
const useStyles = makeStyles((theme: Theme) => {
return ({
@@ -56,6 +57,11 @@ const useStyles = makeStyles((theme: Theme) => {
width: theme.spacing(10)
// justifyContent: "center",
},
+ deviceContainer: {
+ margin: theme.spacing(1),
+ display: "flex",
+ width: theme.spacing(10)
+ },
descriptionCellContainer: {
margin: theme.spacing(1),
marginLeft: theme.spacing(2),
@@ -67,7 +73,7 @@ const useStyles = makeStyles((theme: Theme) => {
margin: theme.spacing(1),
marginLeft: theme.spacing(2),
display: "flex",
- width: theme.spacing(18)
+ minWidth: theme.spacing(10)
// justifyContent: "center",
},
green: {
@@ -140,9 +146,22 @@ export default function Devices() {
// const [totalGroups, setTotalGroups] = useState(0);
const [groupPermissions, setGroupPermissions] = useState([])
+ const [groupsLoaded, setGroupsLoaded] = useState(false)
const groupID = useParams<{ groupID: string }>()?.groupID ?? "all";
- const [tab, setTab] = useState(groupID==="all" ? groupID : groupID);
+ // const [tab, setTab] = useState(groupID==="all" ? groupID : groupID);
+ const [tab, setTab] = useState(() => {
+ console.log("groupID: "+groupID)
+ if (groupID!=="all") return groupID
+ const stored = sessionStorage.getItem(location.pathname+"-groups-tab");
+ console.log("stored: "+stored)
+ return stored !== null ? stored : "all";
+ });
+
+ useEffect(() => {
+ console.log(tab)
+ sessionStorage.setItem(location.pathname+"-groups-tab", tab);
+ }, [tab]);
const [selectedGroup, setSelectedGroup] = useState(undefined);
const [groupSettingsMode, setGroupSettingsMode] = useState<
@@ -184,7 +203,7 @@ export default function Devices() {
useEffect(() => {
setGroupPermissions([])
- if (tab === "all") return
+ if (tab === "all" || !getGroup()) return
groupAPI.getGroupPermissions(getGroup().id()).then(resp => {
setGroupPermissions(resp.data.permissions)
})
@@ -232,7 +251,7 @@ export default function Devices() {
};
const getKeys = () => {
- if (tab !== "all") {
+ if (tab !== "all" && getGroup()) {
let keys = getContextKeys()
//keys.splice(keys.length - 1, 0, getGroup().id().toString());
keys.push(getGroup().id().toString());
@@ -274,11 +293,13 @@ export default function Devices() {
updateGroups(newGroups)
}).finally(() => {
setGroupsLoading(false)
+ setGroupsLoaded(true)
})
}
const loadDevices = () => {
setDevicesLoading(true)
+ if (!groupsLoaded) return
deviceAPI.list(
limit,
page*limit,
@@ -316,7 +337,7 @@ export default function Devices() {
useEffect(() => {
loadDevices()
- }, [limit, page, order, orderBy, fieldContains, search, tab, as])
+ }, [limit, page, order, orderBy, fieldContains, search, tab, as, groupsLoaded])
useEffect(() => {
loadGroups()
@@ -371,12 +392,14 @@ export default function Devices() {
let columns: Column[] = [
{
title: "State",
+ // cellStyle: {width: 100000},
// sortKey: "state",
render: (device: Device) => {
const status = device.status ?? pond.DeviceStatus.create()
const deviceStateHelper = getDeviceStateHelper(status.state);
return (
+ {/* */}
{deviceStateHelper.icon}
)
@@ -391,10 +414,12 @@ export default function Devices() {
},
{
title: "Device",
+ cellStyle: { width: 160 },
sortKey: "name",
render: (device: Device) => {
return (
-
+
+ {/* // */}
{
const description = device.settings?.description ?? ""
let size = (hasCo2 && !groupGas) ? 26 : 36
return (
-
+
{description.length > size
@@ -680,9 +706,7 @@ export default function Devices() {
dense
>
-
+
@@ -692,10 +716,7 @@ export default function Devices() {
dense
>
-
+
@@ -703,6 +724,14 @@ export default function Devices() {
)
}
+ useEffect(() => {
+ console.log('Current tab value:', tab, typeof tab);
+ }, [tab]);
+
+ if (!groupsLoaded) return (
+
+ )
+
return(
}/>
: groups.map((group, index) => {
if (group.id()) return (
- {group.name()}} key={"group-tab-"+index}/>
+ {group.name()}} key={"group-tab-"+index}/>
)
})}
} onClick={() => openGroupSettings(undefined, "add")} />
@@ -753,6 +782,7 @@ export default function Devices() {
orderBy={orderBy}
setOrderBy={setOrderBy}
endTitleElement={preferencesButton}
+ resizeable
loadMore={()=>{
let currentRows = cloneDeep(devices)
deviceAPI.list(
@@ -784,7 +814,7 @@ export default function Devices() {
newDevices.push(Device.create(device))
})
setDevices(currentRows.concat(newDevices))
- }).catch(err => {
+ }).catch(_err => {
})
}}