From 8426b3c5e7913bc1ba3c1ee35e1517eb4245d424 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Mon, 8 Aug 2022 15:32:12 +0000 Subject: [PATCH 1/4] resolves #3356 --- site/src/AppRouter.tsx | 21 ++++++++++++- .../components/NavbarView/NavbarView.test.tsx | 30 +++++++++++++++++++ site/src/components/NavbarView/NavbarView.tsx | 9 ++++++ site/src/pages/AuditPage/AuditPage.tsx | 8 +++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 site/src/pages/AuditPage/AuditPage.tsx diff --git a/site/src/AppRouter.tsx b/site/src/AppRouter.tsx index d76dbc687da77..b7b0d0e6b9cf0 100644 --- a/site/src/AppRouter.tsx +++ b/site/src/AppRouter.tsx @@ -1,5 +1,5 @@ import { FC, lazy, Suspense } from "react" -import { Route, Routes } from "react-router-dom" +import { Navigate, Route, Routes } from "react-router-dom" import { AuthAndFrame } from "./components/AuthAndFrame/AuthAndFrame" import { RequireAuth } from "./components/RequireAuth/RequireAuth" import { SettingsLayout } from "./components/SettingsLayout/SettingsLayout" @@ -25,6 +25,7 @@ const WorkspaceAppErrorPage = lazy( const TerminalPage = lazy(() => import("./pages/TerminalPage/TerminalPage")) const WorkspacesPage = lazy(() => import("./pages/WorkspacesPage/WorkspacesPage")) const CreateWorkspacePage = lazy(() => import("./pages/CreateWorkspacePage/CreateWorkspacePage")) +const AuditPage = lazy(() => import("./pages/AuditPage/AuditPage")) export const AppRouter: FC = () => ( }> @@ -109,6 +110,24 @@ export const AppRouter: FC = () => ( /> + {/* REMARK: Route under construction + Eventually, we should gate this page + with permissions and licensing */} + + + ) : ( + + + + ) + } + > + + }> } /> } /> diff --git a/site/src/components/NavbarView/NavbarView.test.tsx b/site/src/components/NavbarView/NavbarView.test.tsx index 60740a8a4426b..c0755dbda196e 100644 --- a/site/src/components/NavbarView/NavbarView.test.tsx +++ b/site/src/components/NavbarView/NavbarView.test.tsx @@ -7,6 +7,19 @@ describe("NavbarView", () => { const noop = () => { return } + + const env = process.env + + // REMARK: copying process.env so we don't mutate that object or encounter conflicts between tests + beforeEach(() => { + process.env = { ...env } + }) + + // REMARK: restoring process.env + afterEach(() => { + process.env = env + }) + it("renders content", async () => { // When render() @@ -48,4 +61,21 @@ describe("NavbarView", () => { const element = await screen.findByText("B") expect(element).toBeDefined() }) + + it("audit nav link has the correct href", async () => { + render() + const auditLink = await screen.findByText(navLanguage.audit) + expect((auditLink as HTMLAnchorElement).href).toContain("/audit") + }) + + it("audit nav link is only visible in development", async () => { + process.env = { + ...env, + NODE_ENV: "production", + } + + render() + const auditLink = screen.queryByText(navLanguage.audit) + expect(auditLink).not.toBeInTheDocument() + }) }) diff --git a/site/src/components/NavbarView/NavbarView.tsx b/site/src/components/NavbarView/NavbarView.tsx index d982b35e3ad29..98dc8dd985e44 100644 --- a/site/src/components/NavbarView/NavbarView.tsx +++ b/site/src/components/NavbarView/NavbarView.tsx @@ -21,6 +21,7 @@ export const Language = { workspaces: "Workspaces", templates: "Templates", users: "Users", + audit: "Audit", } const NavItems: React.FC<{ className?: string; linkClassName?: string }> = ({ className }) => { @@ -47,6 +48,14 @@ const NavItems: React.FC<{ className?: string; linkClassName?: string }> = ({ cl {Language.users} + {/* REMARK: the below link is under-construction */} + {process.env.NODE_ENV !== "production" && ( + + + {Language.audit} + + + )} ) } diff --git a/site/src/pages/AuditPage/AuditPage.tsx b/site/src/pages/AuditPage/AuditPage.tsx new file mode 100644 index 0000000000000..c285ea2176eed --- /dev/null +++ b/site/src/pages/AuditPage/AuditPage.tsx @@ -0,0 +1,8 @@ +import { FC } from "react" + +// REMARK: This page is in-progress and hidden from users +const AuditPage: FC = () => { + return
Audit
+} + +export default AuditPage From 7ee0ab0c027cb27b445440a8e9be041e283b6fad Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Mon, 8 Aug 2022 19:57:49 +0000 Subject: [PATCH 2/4] scaffolded out new audit page header resolves #3357 --- .../components/CodeExample/CodeExample.tsx | 14 ++++- site/src/components/CopyButton/CopyButton.tsx | 8 ++- site/src/components/Stack/Stack.tsx | 23 ++++---- .../components/Tooltips/AuditHelpTooltip.tsx | 16 +++++ site/src/components/Tooltips/index.ts | 1 + site/src/pages/AuditPage/AuditPage.tsx | 3 +- site/src/pages/AuditPage/AuditPageView.tsx | 59 +++++++++++++++++++ 7 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 site/src/components/Tooltips/AuditHelpTooltip.tsx create mode 100644 site/src/pages/AuditPage/AuditPageView.tsx diff --git a/site/src/components/CodeExample/CodeExample.tsx b/site/src/components/CodeExample/CodeExample.tsx index 95adc25ad4fc3..6736c103a4b09 100644 --- a/site/src/components/CodeExample/CodeExample.tsx +++ b/site/src/components/CodeExample/CodeExample.tsx @@ -8,18 +8,28 @@ export interface CodeExampleProps { code: string className?: string buttonClassName?: string + tooltipTitle?: string } /** * Component to show single-line code examples, with a copy button */ -export const CodeExample: FC = ({ code, className, buttonClassName }) => { +export const CodeExample: FC = ({ + code, + className, + buttonClassName, + tooltipTitle, +}) => { const styles = useStyles() return (
{code} - +
) } diff --git a/site/src/components/CopyButton/CopyButton.tsx b/site/src/components/CopyButton/CopyButton.tsx index 030ca4623a59a..844467258fe15 100644 --- a/site/src/components/CopyButton/CopyButton.tsx +++ b/site/src/components/CopyButton/CopyButton.tsx @@ -11,6 +11,11 @@ interface CopyButtonProps { ctaCopy?: string wrapperClassName?: string buttonClassName?: string + tooltipTitle?: string +} + +const Language = { + tooltipTitle: "Copy to clipboard", } /** @@ -21,6 +26,7 @@ export const CopyButton: React.FC = ({ ctaCopy, wrapperClassName = "", buttonClassName = "", + tooltipTitle = Language.tooltipTitle, }) => { const styles = useStyles() const [isCopied, setIsCopied] = useState(false) @@ -56,7 +62,7 @@ export const CopyButton: React.FC = ({ } return ( - +
+ const useStyles = makeStyles((theme) => ({ stack: { display: "flex", flexDirection: ({ direction }: StyleProps) => direction, - gap: ({ spacing }: StyleProps) => theme.spacing(spacing), + gap: ({ spacing }: StyleProps) => spacing && theme.spacing(spacing), alignItems: ({ alignItems }: StyleProps) => alignItems, + justifyContent: ({ justifyContent }: StyleProps) => justifyContent, [theme.breakpoints.down("sm")]: { width: "100%", @@ -24,21 +29,15 @@ const useStyles = makeStyles((theme) => ({ }, })) -export interface StackProps { - className?: string - direction?: Direction - spacing?: number - alignItems?: CSSProperties["alignItems"] -} - export const Stack: FC = ({ children, className, direction = "column", spacing = 2, alignItems, + justifyContent, }) => { - const styles = useStyles({ spacing, direction, alignItems }) + const styles = useStyles({ spacing, direction, alignItems, justifyContent }) return
{children}
} diff --git a/site/src/components/Tooltips/AuditHelpTooltip.tsx b/site/src/components/Tooltips/AuditHelpTooltip.tsx new file mode 100644 index 0000000000000..fe22cbd4fbd0f --- /dev/null +++ b/site/src/components/Tooltips/AuditHelpTooltip.tsx @@ -0,0 +1,16 @@ +import { FC } from "react" +import { HelpTooltip, HelpTooltipText, HelpTooltipTitle } from "./HelpTooltip" + +const Language = { + title: "What is an audit log?", + body: "An audit log is a record of events and changes made throughout a system.", +} + +export const AuditHelpTooltip: FC = () => { + return ( + + {Language.title} + {Language.body} + + ) +} diff --git a/site/src/components/Tooltips/index.ts b/site/src/components/Tooltips/index.ts index f2813adc68f0c..e5935792f862c 100644 --- a/site/src/components/Tooltips/index.ts +++ b/site/src/components/Tooltips/index.ts @@ -2,3 +2,4 @@ export { AgentHelpTooltip } from "./AgentHelpTooltip" export { OutdatedHelpTooltip } from "./OutdatedHelpTooltip" export { ResourcesHelpTooltip } from "./ResourcesHelpTooltip" export { WorkspaceHelpTooltip } from "./WorkspaceHelpTooltip" +export { AuditHelpTooltip } from "./AuditHelpTooltip" diff --git a/site/src/pages/AuditPage/AuditPage.tsx b/site/src/pages/AuditPage/AuditPage.tsx index c285ea2176eed..1ee1f465b67cf 100644 --- a/site/src/pages/AuditPage/AuditPage.tsx +++ b/site/src/pages/AuditPage/AuditPage.tsx @@ -1,8 +1,9 @@ import { FC } from "react" +import { AuditPageView } from "./AuditPageView" // REMARK: This page is in-progress and hidden from users const AuditPage: FC = () => { - return
Audit
+ return } export default AuditPage diff --git a/site/src/pages/AuditPage/AuditPageView.tsx b/site/src/pages/AuditPage/AuditPageView.tsx new file mode 100644 index 0000000000000..c284717fe2c9c --- /dev/null +++ b/site/src/pages/AuditPage/AuditPageView.tsx @@ -0,0 +1,59 @@ +import { makeStyles } from "@material-ui/core/styles" +import { CodeExample } from "components/CodeExample/CodeExample" +import { Margins } from "components/Margins/Margins" +import { PageHeader, PageHeaderSubtitle, PageHeaderTitle } from "components/PageHeader/PageHeader" +import { Stack } from "components/Stack/Stack" +import { AuditHelpTooltip } from "components/Tooltips" +import { FC } from "react" + +export const Language = { + title: "Audit", + subtitle: "View events in your audit log.", + tooltipTitle: "Copy to clipboard and try the Coder CLI", +} + +export const AuditPageView: FC = () => { + const styles = useStyles() + + return ( + + + + + + {Language.title} + + + + {Language.subtitle} + + + + + ) +} + +const useStyles = makeStyles((theme) => ({ + headingContainer: { + marginTop: theme.spacing(6), + marginBottom: theme.spacing(5), + flexDirection: "row", + alignItems: "center", + + [theme.breakpoints.down("sm")]: { + flexDirection: "column", + alignItems: "start", + }, + }, + headingStyles: { + paddingTop: "0px", + paddingBottom: "0px", + }, + codeExampleStyles: { + height: "fit-content", + }, +})) From 5ee10a4a2a7a6fd212a58a04d2acc040a380cbc4 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Mon, 8 Aug 2022 20:52:33 +0000 Subject: [PATCH 3/4] added tests and stories --- site/src/components/CopyButton/CopyButton.tsx | 4 ++- .../components/Tooltips/AuditHelpTooltip.tsx | 2 +- .../Tooltips/HelpTooltip/HelpTooltip.tsx | 5 +++ site/src/pages/AuditPage/AuditPage.test.tsx | 32 +++++++++++++++++++ .../pages/AuditPage/AuditPageView.stories.tsx | 16 ++++++++++ 5 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 site/src/pages/AuditPage/AuditPage.test.tsx create mode 100644 site/src/pages/AuditPage/AuditPageView.stories.tsx diff --git a/site/src/components/CopyButton/CopyButton.tsx b/site/src/components/CopyButton/CopyButton.tsx index 844467258fe15..fee7a09fd8a07 100644 --- a/site/src/components/CopyButton/CopyButton.tsx +++ b/site/src/components/CopyButton/CopyButton.tsx @@ -14,8 +14,9 @@ interface CopyButtonProps { tooltipTitle?: string } -const Language = { +export const Language = { tooltipTitle: "Copy to clipboard", + ariaLabel: "Copy to clipboard", } /** @@ -68,6 +69,7 @@ export const CopyButton: React.FC = ({ className={combineClasses([styles.copyButton, buttonClassName])} onClick={copyToClipboard} size="small" + aria-label={Language.ariaLabel} > {isCopied ? ( diff --git a/site/src/components/Tooltips/AuditHelpTooltip.tsx b/site/src/components/Tooltips/AuditHelpTooltip.tsx index fe22cbd4fbd0f..33305668f2f9f 100644 --- a/site/src/components/Tooltips/AuditHelpTooltip.tsx +++ b/site/src/components/Tooltips/AuditHelpTooltip.tsx @@ -1,7 +1,7 @@ import { FC } from "react" import { HelpTooltip, HelpTooltipText, HelpTooltipTitle } from "./HelpTooltip" -const Language = { +export const Language = { title: "What is an audit log?", body: "An audit log is a record of events and changes made throughout a system.", } diff --git a/site/src/components/Tooltips/HelpTooltip/HelpTooltip.tsx b/site/src/components/Tooltips/HelpTooltip/HelpTooltip.tsx index 7c70d9146743a..3bbfc4dab4558 100644 --- a/site/src/components/Tooltips/HelpTooltip/HelpTooltip.tsx +++ b/site/src/components/Tooltips/HelpTooltip/HelpTooltip.tsx @@ -15,6 +15,10 @@ export interface HelpTooltipProps { size?: Size } +export const Language = { + ariaLabel: "tooltip", +} + const HelpTooltipContext = createContext<{ open: boolean; onClose: () => void } | undefined>( undefined, ) @@ -52,6 +56,7 @@ export const HelpTooltip: React.FC = ({ children, open, size = onMouseEnter={() => { setIsOpen(true) }} + aria-label={Language.ariaLabel} > diff --git a/site/src/pages/AuditPage/AuditPage.test.tsx b/site/src/pages/AuditPage/AuditPage.test.tsx new file mode 100644 index 0000000000000..8c98281207e86 --- /dev/null +++ b/site/src/pages/AuditPage/AuditPage.test.tsx @@ -0,0 +1,32 @@ +import { fireEvent, screen } from "@testing-library/react" +import { Language as CopyButtonLanguage } from "components/CopyButton/CopyButton" +import { Language as AuditTooltipLanguage } from "components/Tooltips/AuditHelpTooltip" +import { Language as TooltipLanguage } from "components/Tooltips/HelpTooltip/HelpTooltip" +import { render } from "testHelpers/renderHelpers" +import AuditPage from "./AuditPage" +import { Language as AuditViewLanguage } from "./AuditPageView" + +describe("AuditPage", () => { + it("renders a page with a title and subtitle", async () => { + // When + render() + + // Then + await screen.findByText(AuditViewLanguage.title) + await screen.findByText(AuditViewLanguage.subtitle) + const tooltipIcon = await screen.findByRole("button", { name: TooltipLanguage.ariaLabel }) + fireEvent.mouseOver(tooltipIcon) + expect(await screen.findByText(AuditTooltipLanguage.title)).toBeInTheDocument() + }) + + it("describes the CLI command", async () => { + // When + render() + + // Then + await screen.findByText("coder audit [organization_ID]") // CLI command; untranslated + const copyIcon = await screen.findByRole("button", { name: CopyButtonLanguage.ariaLabel }) + fireEvent.mouseOver(copyIcon) + expect(await screen.findByText(AuditViewLanguage.tooltipTitle)).toBeInTheDocument() + }) +}) diff --git a/site/src/pages/AuditPage/AuditPageView.stories.tsx b/site/src/pages/AuditPage/AuditPageView.stories.tsx new file mode 100644 index 0000000000000..7ad3725855264 --- /dev/null +++ b/site/src/pages/AuditPage/AuditPageView.stories.tsx @@ -0,0 +1,16 @@ +import { ComponentMeta, Story } from "@storybook/react" +import { AuditPageView } from "./AuditPageView" + +export default { + title: "pages/AuditPageView", + component: AuditPageView, +} as ComponentMeta + +const Template: Story = (args) => + +export const AuditPage = Template.bind({}) + +export const AuditPageSmallViewport = Template.bind({}) +AuditPageSmallViewport.parameters = { + chromatic: { viewports: [600] }, +} From a4506d7fce83fcfea4301fa431af658475728f04 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Mon, 8 Aug 2022 21:10:57 +0000 Subject: [PATCH 4/4] run prettier --- site/src/components/Tooltips/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/components/Tooltips/index.ts b/site/src/components/Tooltips/index.ts index e5935792f862c..4f7eabac682c7 100644 --- a/site/src/components/Tooltips/index.ts +++ b/site/src/components/Tooltips/index.ts @@ -1,5 +1,5 @@ export { AgentHelpTooltip } from "./AgentHelpTooltip" +export { AuditHelpTooltip } from "./AuditHelpTooltip" export { OutdatedHelpTooltip } from "./OutdatedHelpTooltip" export { ResourcesHelpTooltip } from "./ResourcesHelpTooltip" export { WorkspaceHelpTooltip } from "./WorkspaceHelpTooltip" -export { AuditHelpTooltip } from "./AuditHelpTooltip"