added smart bread crumbs
This commit is contained in:
parent
23bcb467e9
commit
cd986c4f56
3 changed files with 351 additions and 2 deletions
336
src/common/SmartBreadcrumb.tsx
Normal file
336
src/common/SmartBreadcrumb.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue