fleet/frontend/layouts/CoreLayout/CoreLayout.tsx
Jacob Shandling 8a5569cd1b
9349 new controls page (#9431)
# Addresses #9349

# Implements
https://www.loom.com/share/bbf8d6f97fe74e65a0c9a394f1bda3f1
- New Controls page, only visible to Global|Team Admins|Maintainers
- Header for free users is 'Controls', for premium is a teams filter
dropdown that defaults to 'No teams,' which filters via updating the URL
query param "team_id"
    - Includes tabs macUpdates (default) and macSettings
- Cleaned up how site nav items are conditionally included/excluded
based on authorization – see
`frontend/components/top_nav/SiteTopNav/navItems.ts`
- Updated masthead styles: Removed icons from site nav links; updated
colors and spacing; Updated default user avatar TBD in separate PR
(waiting on guidance)

# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/` 
- [x] Updated testing suite inventory
- [x] Manual QA for all new/changed functionality

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
2023-01-26 11:33:54 -08:00

145 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useContext } from "react";
import { InjectedRouter } from "react-router";
import { AppContext } from "context/app";
import { NotificationContext } from "context/notification";
import { TableContext } from "context/table";
import paths from "router/paths";
import useDeepEffect from "hooks/useDeepEffect";
import FlashMessage from "components/FlashMessage";
import SiteTopNav from "components/top_nav/SiteTopNav";
import CustomLink from "components/CustomLink";
import { INotification } from "interfaces/notification";
import { licenseExpirationWarning } from "utilities/helpers";
import smallScreenImage from "../../../assets/images/small-screen-160x80@2x.png";
interface ICoreLayoutProps {
children: React.ReactNode;
router: InjectedRouter; // v3
}
const expirationMessage = (
<>
Your license for Fleet Premium is about to expire. If youd like to renew or
have questions about downgrading,{" "}
<CustomLink
url="https://fleetdm.com/docs/using-fleet/faq#how-do-i-downgrade-from-fleet-premium-to-fleet-free"
text="please head to the Fleet documentation"
newTab
multiline
/>
</>
);
const CoreLayout = ({ children, router }: ICoreLayoutProps) => {
const { config, currentUser, isPremiumTier } = useContext(AppContext);
const { notification, hideFlash } = useContext(NotificationContext);
const { setResetSelectedRows } = useContext(TableContext);
const [showExpirationFlashMessage, setShowExpirationFlashMessage] = useState(
false
);
// on success of an action, the table will reset its checkboxes.
// setTimeout is to help with race conditions as table reloads
// in some instances (i.e. Manage Hosts)
useDeepEffect(() => {
if (notification?.alertType === "success") {
setTimeout(() => {
setResetSelectedRows(true);
setTimeout(() => {
setResetSelectedRows(false);
}, 300);
}, 0);
}
setShowExpirationFlashMessage(
licenseExpirationWarning(config?.license.expiration || "")
);
}, [notification]);
const onLogoutUser = async () => {
const { LOGOUT } = paths;
router.push(LOGOUT);
};
const onNavItemClick = (path: string) => {
return (evt: React.MouseEvent<HTMLButtonElement>) => {
evt.preventDefault();
if (path.indexOf("http") !== -1) {
global.window.open(path, "_blank");
return false;
}
router.push(path);
return false;
};
};
const onUndoActionClick = (undoAction?: () => void) => {
return (evt: React.MouseEvent<HTMLButtonElement>) => {
evt.preventDefault();
if (undoAction) {
undoAction();
}
hideFlash();
};
};
const fullWidthFlash = !currentUser;
const expirationNotification: INotification = {
alertType: "warning-filled",
isVisible: true,
message: expirationMessage,
};
if (!currentUser || !config) {
return null;
}
const { pathname } = global.window.location;
return (
<div className="app-wrap">
<div className="overlay">
<img src={smallScreenImage} alt="Unsupported screen size" />
<div className="overlay__text">
<h1>This screen size is not supported yet.</h1>
<p>Please enlarge your browser or try again on a computer.</p>
</div>
</div>
<nav className="site-nav-container">
<SiteTopNav
config={config}
onLogoutUser={onLogoutUser}
onNavItemClick={onNavItemClick}
pathname={pathname}
currentUser={currentUser}
/>
</nav>
<div className="core-wrapper">
{isPremiumTier && showExpirationFlashMessage && (
<FlashMessage
fullWidth={fullWidthFlash}
notification={expirationNotification}
onRemoveFlash={() =>
setShowExpirationFlashMessage(!showExpirationFlashMessage)
}
/>
)}
<FlashMessage
fullWidth={fullWidthFlash}
notification={notification}
onRemoveFlash={hideFlash}
onUndoActionClick={onUndoActionClick}
/>
{children}
</div>
</div>
);
};
export default CoreLayout;