added smart bread crumbs

This commit is contained in:
Carter 2024-12-13 10:48:43 -06:00
parent 23bcb467e9
commit cd986c4f56
3 changed files with 351 additions and 2 deletions

View file

@ -0,0 +1,336 @@
import {
Breadcrumbs,
Chip,
IconButton,
Link,
LinkProps,
Skeleton,
Theme,
useTheme
} from "@mui/material";
import { Replay } from "@mui/icons-material";
// import Link, { LinkProps } from "@material-ui/core/Link";
// import { Skeleton } from "@mui/l";
import { useMobile } from "hooks";
// import { MatchParams } from "navigation/Routes";
import React, { ReactNode } from "react";
import { useLocation } from "react-router";
import { Link as RouterLink } from "react-router-dom";
import { or } from "utils/types";
import { makeStyles } from "@mui/styles";
import { getThemeType } from "theme/themeType";
const useStyles = makeStyles((theme: Theme) => {
// const isMobile = useMobile()
return ({
chip: {
maxWidth: "150px",
[theme.breakpoints.up("md")]: {
maxWidth: "200px"
},
color: "inherit",
textDecoration: "none",
'&:hover': {
color: "inherit"
}
},
textOverflow: {
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
textTransform: "capitalize",
textDecoration: "none"
}
});
});
interface Props {
deviceName?: string;
componentName?: string;
groupName?: string;
binName?: string;
reportTarget?: string;
loading?: boolean;
reload?: () => void;
}
interface LinkRouterProps extends LinkProps {
to: string;
replace?: boolean;
}
const LinkRouter = (props: LinkRouterProps) => <Link {...props} component={RouterLink as any} />;
export default function SmartBreadcrumb(props: Props) {
const theme = useTheme();
const location = useLocation();
const isMobile = useMobile();
const classes = useStyles();
const { loading, reload } = props;
const groupID = (): string => {
const regexMatch = or(location.pathname.match(/\/groups\/([^/]+)/), [])
return or(regexMatch[1], "0").toString();
};
const deviceID = (): string => {
const regexMatch = or(location.pathname.match(/\/devices\/([^/]+)/), [])
return or(regexMatch[1], "0").toString();
};
const mineKey = (): string => {
const regexMatch = or(location.pathname.match(/\/mines\/([^/]+)/), [])
return or(regexMatch[1], "0").toString();
};
const jobsiteKey = (): string => {
const regexMatch = or(location.pathname.match(/\/jobs\/([^/]+)/), [])
return or(regexMatch[1], "0").toString();
};
const componentID = (): string => {
const regexMatch = or(location.pathname.match(/\/components\/([^/]+)/), [])
return or(regexMatch[1], "0").toString();
};
const reportID = (): string => {
const regexMatch = or(location.pathname.match(/\/reports\/([^/]+)/), [])
return or(regexMatch[1], "0").toString();
};
const binID = (): string => {
const regexMatch = or(location.pathname.match(/\/bins\/([^/]+)/), [])
return or(regexMatch[1], "0").toString();
};
const reportIDShort = (): string => {
return reportID().split("-")[0];
};
// Paths
const dashboardPath = (): string => {
return "/";
};
const groupsPath = (): string => {
return "/groups";
};
const groupPath = (): string => {
return groupsPath() + "/" + groupID();
};
const devicesPath = (): string => {
return "/devices";
};
const devicePath = (): string => {
return devicesPath() + "/" + deviceID();
};
const minesPath = (): string => {
return "/mines";
};
const minePath = (): string => {
return minesPath() + "/" + mineKey();
};
const jobsitesPath = (): string => {
return "/jobsites";
};
const jobsitePath = (): string => {
return jobsitesPath() + "/" + jobsiteKey();
};
const componentsPath = (): string => {
return "/components";
};
const componentPath = (): string => {
return componentsPath() + "/" + componentID();
};
const securityPath = (): string => {
return "/security";
};
const reportPath = (): string => {
return securityPath() + "/" + reportID();
};
const groupDevicesPath = (): string => {
return groupPath() + devicesPath();
};
const groupDevicePath = (): string => {
return groupPath() + devicePath();
};
const groupComponentsPath = (): string => {
return groupPath() + componentsPath();
};
const groupComponentPath = (): string => {
return groupPath() + componentPath();
};
const historyPath = (): string => {
return "/history";
};
const deviceHistoryPath = (): string => {
return devicePath() + historyPath();
};
const groupDeviceHistoryPath = (): string => {
return groupDevicePath() + historyPath();
};
const firmwarePath = (): string => {
return "/firmware";
};
const usersPath = (): string => {
return "/users";
};
const binsPath = (): string => {
return "/bins";
};
const binPath = (): string => {
return binsPath() + "/" + binID();
};
const getBreadcrumbMap = (): { [key: string]: string } => {
const { groupName, deviceName, componentName, reportTarget, binName } = props;
const deviceLabel: string = deviceName ? deviceName : "Device " + deviceID();
const componentLabel: string = componentName ? componentName : "Component " + componentID();
const binLabel: string = binName ?? "Bin " + binID();
const mineLabel: string = "Mine Site";
const jobsiteLabel: string = "Job Site";
return {
[dashboardPath()]: "Dashboard",
[groupsPath()]: "Groups",
[groupPath()]: groupName ? groupName : "Group " + groupID(),
[devicesPath()]: "Devices",
[devicePath()]: deviceLabel,
[minesPath()]: "Mines",
[minePath()]: mineLabel,
[jobsitesPath()]: "Job Sites",
[jobsitePath()]: jobsiteLabel,
[componentsPath()]: "Components",
[componentPath()]: componentLabel,
[securityPath()]: "Security",
[reportPath()]: "Report " + reportIDShort() + (reportTarget ? " (" + reportTarget + ")" : ""),
[groupDevicePath()]: deviceLabel,
[groupComponentPath()]: componentLabel,
[deviceHistoryPath()]: "History",
[groupDeviceHistoryPath()]: "History",
[firmwarePath()]: "Firmware",
[usersPath()]: "Users",
[binsPath()]: "Bins",
[binPath()]: binLabel
};
};
const breadcrumbBlacklist = (): string[] => {
return [dashboardPath(), componentsPath(), groupDevicesPath(), groupComponentsPath()];
};
const breadcrumbLinks = (): ReactNode[] => {
const breadcrumbMap = getBreadcrumbMap();
let links: ReactNode[] = [];
const pathnames = location.pathname.split("/").filter((x: any) => x);
const blacklist = breadcrumbBlacklist();
// console.log(pathnames)
if (pathnames.length < 1) {
return [linkComponent("/", "Dashboard", true)];
}
pathnames.forEach((_value: any, index: any) => {
const lastPath = index === pathnames.length - 1;
const to = `/${pathnames.slice(0, index + 1).join("/")}`;
let label = breadcrumbMap[to];
let result = to.split("/").filter(str => str !== "");
// console.log(result)
if (!label) {
if (result.length > 1) {
if (result[result.length - 1] !== "components") {
label = breadcrumbMap["/" + result[result.length - 1]];
console.log(label)
}
}
if (!label && result[result.length - 1] !== "components") {
label = breadcrumbMap["/" + result[result.length - 2] + "/" + result[result.length - 1]];
console.log(label)
}
}
if (!blacklist.includes(to) && label) {
links.push(linkComponent(to, label, lastPath));
}
});
// console.log(links)
return links;
};
const linkComponent = (to: string, label: string, lastPath: boolean) => {
return (
<Chip
key={to}
variant={lastPath ? "filled" : "outlined"}
label={
<LinkRouter
color={lastPath ? "textPrimary" : "textSecondary"}
variant="subtitle1"
to={to}
sx={{ '&:hover': { color: getThemeType() === "dark" ? 'white' : "black" } }}
className={classes.textOverflow}>
{label}
</LinkRouter>
}
className={classes.chip}
/>
);
};
const localReload = () => {
if (reload) {
reload();
} else {
}
};
if (loading === true) return <Skeleton variant="text" width="100%" />;
return (
<React.Fragment>
<Breadcrumbs
maxItems={isMobile ? 1 : 3}
itemsBeforeCollapse={0}
aria-label="Location Breadcrumb">
{breadcrumbLinks()}
</Breadcrumbs>
{reload && (
<IconButton
color="inherit"
size="small"
style={{ marginLeft: theme.spacing(1) }}
onClick={localReload}>
<Replay />
</IconButton>
)}
</React.Fragment>
);
}

View file

@ -8,6 +8,7 @@ import { useLocation, useParams } from "react-router-dom";
import PageContainer from "./PageContainer";
import { useMobile } from "hooks";
import LoadingScreen from "app/LoadingScreen";
import SmartBreadcrumb from "common/SmartBreadcrumb";
const useStyles = makeStyles((theme: Theme) => {
// const isMobile = useMobile()
@ -52,9 +53,10 @@ export default function DevicePage() {
return (
<PageContainer padding={isMobile ? 0 : 2}>
<Typography>
{/* <Typography>
{device.name()}
</Typography>
</Typography> */}
<SmartBreadcrumb />
</PageContainer>
);
}

View file

@ -234,6 +234,17 @@ function options(themeType: "light" | "dark"): ThemeOptions {
},
},
},
MuiLink: {
styleOverrides: {
root: {
color: 'inherit', // Default link color
textDecoration: 'none', // Remove underline if desired
'&:hover': {
// color: 'red !important', // Your hover color
},
},
},
},
// MuiDataGrid: {
// styleOverrides: {
// root: {