-
Notifications
You must be signed in to change notification settings - Fork 929
refactor: update the navbar to match the new designs #15964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
3900600
916c0a7
8837484
f365421
072a6d8
a040a3b
2a79316
1b0c075
7956d56
7f9a95d
7e11d46
07ce677
0699cb4
2830801
08f92e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ import { | |
MockMemberPermissions, | ||
} from "testHelpers/entities"; | ||
import { server } from "testHelpers/server"; | ||
import { Language } from "./NavbarView"; | ||
|
||
/** | ||
* The LicenseBanner, mounted above the AppRouter, fetches entitlements. Thus, to test their | ||
|
@@ -26,7 +25,7 @@ describe("Navbar", () => { | |
await userEvent.click(deploymentMenu); | ||
await waitFor( | ||
() => { | ||
const link = screen.getByText(Language.audit); | ||
const link = screen.getByText("Audit Logs"); | ||
expect(link).toBeDefined(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this check needed since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You’re right, it’s not needed. |
||
}, | ||
{ timeout: 2000 }, | ||
|
@@ -41,7 +40,7 @@ describe("Navbar", () => { | |
await userEvent.click(deploymentMenu); | ||
await waitFor( | ||
() => { | ||
const link = screen.queryByText(Language.audit); | ||
const link = screen.queryByText("Audit Logs"); | ||
expect(link).toBe(null); | ||
}, | ||
{ timeout: 2000 }, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ import userEvent from "@testing-library/user-event"; | |
import type { ProxyContextValue } from "contexts/ProxyContext"; | ||
import { MockPrimaryWorkspaceProxy, MockUser } from "testHelpers/entities"; | ||
import { renderWithAuth } from "testHelpers/renderHelpers"; | ||
import { NavbarView, Language as navLanguage } from "./NavbarView"; | ||
import { NavbarView } from "./NavbarView"; | ||
|
||
const proxyContextValue: ProxyContextValue = { | ||
proxy: { | ||
|
@@ -36,7 +36,7 @@ describe("NavbarView", () => { | |
canViewAuditLog | ||
/>, | ||
); | ||
const workspacesLink = await screen.findByText(navLanguage.workspaces); | ||
const workspacesLink = await screen.findByText("Workspaces"); | ||
expect((workspacesLink as HTMLAnchorElement).href).toContain("/workspaces"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this be swapped for a const workspacesLink = await screen.findByRole<HTMLAnchorElement>("link", {
name: /Workspaces/i
});
expect(workspacesLink.href).toContain("/workspaces"); Same goes for the other links There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m going to stick with |
||
}); | ||
|
||
|
@@ -54,7 +54,7 @@ describe("NavbarView", () => { | |
canViewAuditLog | ||
/>, | ||
); | ||
const templatesLink = await screen.findByText(navLanguage.templates); | ||
const templatesLink = await screen.findByText("Templates"); | ||
expect((templatesLink as HTMLAnchorElement).href).toContain("/templates"); | ||
}); | ||
|
||
|
@@ -74,7 +74,7 @@ describe("NavbarView", () => { | |
); | ||
const deploymentMenu = await screen.findByText("Admin settings"); | ||
await userEvent.click(deploymentMenu); | ||
const auditLink = await screen.findByText(navLanguage.audit); | ||
const auditLink = await screen.findByText("Audit Logs"); | ||
expect((auditLink as HTMLAnchorElement).href).toContain("/audit"); | ||
}); | ||
|
||
|
@@ -94,9 +94,7 @@ describe("NavbarView", () => { | |
); | ||
const deploymentMenu = await screen.findByText("Admin settings"); | ||
await userEvent.click(deploymentMenu); | ||
const deploymentSettingsLink = await screen.findByText( | ||
navLanguage.deployment, | ||
); | ||
const deploymentSettingsLink = await screen.findByText("Deployment"); | ||
expect((deploymentSettingsLink as HTMLAnchorElement).href).toContain( | ||
"/deployment/general", | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,24 @@ | ||
import { type Interpolation, type Theme, css, useTheme } from "@emotion/react"; | ||
import MenuIcon from "@mui/icons-material/Menu"; | ||
import Drawer from "@mui/material/Drawer"; | ||
import IconButton from "@mui/material/IconButton"; | ||
import type * as TypesGen from "api/typesGenerated"; | ||
import { ExternalImage } from "components/ExternalImage/ExternalImage"; | ||
import { CoderIcon } from "components/Icons/CoderIcon"; | ||
import type { ProxyContextValue } from "contexts/ProxyContext"; | ||
import { type FC, useState } from "react"; | ||
import { Link, NavLink, useLocation } from "react-router-dom"; | ||
import type { FC } from "react"; | ||
import { NavLink, useLocation } from "react-router-dom"; | ||
import { DeploymentDropdown } from "./DeploymentDropdown"; | ||
import { ProxyMenu } from "./ProxyMenu"; | ||
import { UserDropdown } from "./UserDropdown/UserDropdown"; | ||
import { cn } from "utils/cn"; | ||
import { Button } from "components/Button/Button"; | ||
import { ChevronRightIcon, MenuIcon } from "lucide-react"; | ||
import { | ||
DropdownMenu, | ||
DropdownMenuContent, | ||
DropdownMenuItem, | ||
DropdownMenuTrigger, | ||
} from "components/DropdownMenu/DropdownMenu"; | ||
import { Avatar } from "components/Avatar/Avatar"; | ||
import { Latency } from "components/Latency/Latency"; | ||
|
||
export const Language = { | ||
workspaces: "Workspaces", | ||
templates: "Templates", | ||
users: "Users", | ||
audit: "Audit Logs", | ||
deployment: "Deployment", | ||
}; | ||
export interface NavbarViewProps { | ||
logo_url?: string; | ||
user?: TypesGen.User; | ||
|
@@ -41,6 +40,9 @@ const linkClassNames = { | |
active: "text-content-primary", | ||
}; | ||
|
||
const mobileDropdownItemClassName = | ||
"px-9 h-[60px] border-0 border-b border-solid"; | ||
|
||
export const NavbarView: FC<NavbarViewProps> = ({ | ||
user, | ||
logo_url, | ||
|
@@ -55,40 +57,8 @@ export const NavbarView: FC<NavbarViewProps> = ({ | |
canViewAuditLog, | ||
proxyContextValue, | ||
}) => { | ||
const [isDrawerOpen, setIsDrawerOpen] = useState(false); | ||
|
||
return ( | ||
<div className="border-0 border-b border-solid h-[72px] flex items-center leading-none px-6"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They shouldn’t, but since we’re not using Tailwind’s preflight and are still relying on MUI’s reset, the border doesn’t apply correctly without those classes. |
||
<IconButton | ||
aria-label="Open menu" | ||
css={styles.mobileMenuButton} | ||
onClick={() => { | ||
setIsDrawerOpen(true); | ||
}} | ||
size="large" | ||
> | ||
<MenuIcon /> | ||
</IconButton> | ||
|
||
<Drawer | ||
anchor="left" | ||
open={isDrawerOpen} | ||
onClose={() => setIsDrawerOpen(false)} | ||
> | ||
<div css={{ width: 250 }}> | ||
<div css={styles.drawerHeader}> | ||
<div css={["h-7", styles.drawerLogo]}> | ||
{logo_url ? ( | ||
<ExternalImage src={logo_url} alt="Custom Logo" /> | ||
) : ( | ||
<CoderIcon /> | ||
)} | ||
</div> | ||
</div> | ||
<NavItems /> | ||
</div> | ||
</Drawer> | ||
|
||
<NavLink to="/workspaces"> | ||
{logo_url ? ( | ||
<ExternalImage className="h-7" src={logo_url} alt="Custom Logo" /> | ||
|
@@ -99,7 +69,7 @@ export const NavbarView: FC<NavbarViewProps> = ({ | |
|
||
<NavItems className="ml-4" /> | ||
|
||
<div className="flex items-center gap-3 ml-auto"> | ||
<div className=" hidden md:flex items-center gap-3 ml-auto"> | ||
{proxyContextValue && ( | ||
<ProxyMenu proxyContextValue={proxyContextValue} /> | ||
)} | ||
|
@@ -130,10 +100,70 @@ export const NavbarView: FC<NavbarViewProps> = ({ | |
/> | ||
)} | ||
</div> | ||
|
||
<MobileMenu proxyContextValue={proxyContextValue} user={user} /> | ||
</div> | ||
); | ||
}; | ||
|
||
type MobileMenuProps = { | ||
proxyContextValue?: ProxyContextValue; | ||
user?: TypesGen.User; | ||
}; | ||
|
||
const MobileMenu: FC<MobileMenuProps> = ({ proxyContextValue, user }) => { | ||
const selectedProxy = proxyContextValue?.proxy.proxy; | ||
const latency = selectedProxy | ||
? proxyContextValue?.proxyLatencies[selectedProxy?.id] | ||
: undefined; | ||
|
||
return ( | ||
<DropdownMenu> | ||
<DropdownMenuTrigger asChild> | ||
<Button | ||
aria-label="Open Menu" | ||
size="icon" | ||
variant="ghost" | ||
className="ml-auto md:hidden" | ||
> | ||
<MenuIcon /> | ||
</Button> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent className="w-screen border-0 p-0" sideOffset={17}> | ||
{selectedProxy && ( | ||
<DropdownMenuItem className={mobileDropdownItemClassName}> | ||
Workspace proxy settings: | ||
<span className="leading-[0px] flex items-center gap-1"> | ||
<img | ||
className="w-4 h-4" | ||
src={selectedProxy.icon_url} | ||
alt={selectedProxy.name} | ||
/> | ||
{latency && <Latency latency={latency.latencyMS} />} | ||
</span> | ||
<ChevronRightIcon className="ml-auto" /> | ||
</DropdownMenuItem> | ||
)} | ||
<DropdownMenuItem className={mobileDropdownItemClassName}> | ||
Admin settings | ||
<ChevronRightIcon className="ml-auto" /> | ||
</DropdownMenuItem> | ||
<DropdownMenuItem className={mobileDropdownItemClassName}> | ||
Docs | ||
</DropdownMenuItem> | ||
<DropdownMenuItem className={mobileDropdownItemClassName}> | ||
<Avatar | ||
src={user?.avatar_url} | ||
fallback={user?.name || user?.username} | ||
/> | ||
User settings | ||
<ChevronRightIcon className="ml-auto" /> | ||
</DropdownMenuItem> | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
); | ||
}; | ||
|
||
interface NavItemsProps { | ||
className?: string; | ||
} | ||
|
@@ -155,7 +185,7 @@ const NavItems: FC<NavItemsProps> = ({ className }) => { | |
}} | ||
to="/workspaces" | ||
> | ||
{Language.workspaces} | ||
Workspaces | ||
</NavLink> | ||
<NavLink | ||
className={({ isActive }) => { | ||
|
@@ -166,26 +196,8 @@ const NavItems: FC<NavItemsProps> = ({ className }) => { | |
}} | ||
to="/templates" | ||
> | ||
{Language.templates} | ||
Templates | ||
</NavLink> | ||
</nav> | ||
); | ||
}; | ||
|
||
const styles = { | ||
mobileMenuButton: (theme) => css` | ||
${theme.breakpoints.up("md")} { | ||
display: none; | ||
} | ||
`, | ||
|
||
drawerHeader: { | ||
padding: 16, | ||
paddingTop: 32, | ||
paddingBottom: 32, | ||
}, | ||
drawerLogo: { | ||
padding: 0, | ||
maxHeight: 40, | ||
}, | ||
} satisfies Record<string, Interpolation<Theme>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we update these to be role selectors, too?