diff --git a/src/common/SmartBreadcrumb.tsx b/src/common/SmartBreadcrumb.tsx
new file mode 100644
index 0000000..7661f5f
--- /dev/null
+++ b/src/common/SmartBreadcrumb.tsx
@@ -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) => ;
+
+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 (
+
+ {label}
+
+ }
+ className={classes.chip}
+ />
+ );
+ };
+
+ const localReload = () => {
+ if (reload) {
+ reload();
+ } else {
+ }
+ };
+
+ if (loading === true) return ;
+
+ return (
+
+
+ {breadcrumbLinks()}
+
+ {reload && (
+
+
+
+ )}
+
+ );
+}
diff --git a/src/pages/Device.tsx b/src/pages/Device.tsx
index 0b4985b..6f46dda 100644
--- a/src/pages/Device.tsx
+++ b/src/pages/Device.tsx
@@ -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 (
-
+ {/*
{device.name()}
-
+ */}
+
);
}
\ No newline at end of file
diff --git a/src/theme/theme.ts b/src/theme/theme.ts
index 44625f9..e05b0f9 100644
--- a/src/theme/theme.ts
+++ b/src/theme/theme.ts
@@ -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: {