From 75ef1f4b264d0958d8c25dadf155e015c40400da Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Thu, 7 Apr 2022 16:44:08 -0300 Subject: [PATCH] feat: Add preferences pages (#893) --- site/src/AppRouter.tsx | 23 ++++++----- site/src/components/Panel/Panel.stories.tsx | 21 ---------- site/src/components/Preferences/Layout.tsx | 34 ++++++++++++++++ .../components/Sidebar/Sidebar.stories.tsx | 20 ---------- .../components/TabPanel/TabPanel.stories.tsx | 20 ++++++++++ .../TabPanel/TabSidebar.stories.tsx | 19 +++++++++ .../index.tsx => TabPanel/TabSidebar.tsx} | 40 +++++++++---------- .../components/{Panel => TabPanel}/index.tsx | 12 +++--- site/src/pages/preferences/account.tsx | 11 +++++ site/src/pages/preferences/index.tsx | 15 ------- .../src/pages/preferences/linked-accounts.tsx | 12 ++++++ site/src/pages/preferences/security.tsx | 11 +++++ site/src/pages/preferences/ssh-keys.tsx | 12 ++++++ 13 files changed, 155 insertions(+), 95 deletions(-) delete mode 100644 site/src/components/Panel/Panel.stories.tsx create mode 100644 site/src/components/Preferences/Layout.tsx delete mode 100644 site/src/components/Sidebar/Sidebar.stories.tsx create mode 100644 site/src/components/TabPanel/TabPanel.stories.tsx create mode 100644 site/src/components/TabPanel/TabSidebar.stories.tsx rename site/src/components/{Sidebar/index.tsx => TabPanel/TabSidebar.tsx} (67%) rename site/src/components/{Panel => TabPanel}/index.tsx (84%) create mode 100644 site/src/pages/preferences/account.tsx delete mode 100644 site/src/pages/preferences/index.tsx create mode 100644 site/src/pages/preferences/linked-accounts.tsx create mode 100644 site/src/pages/preferences/security.tsx create mode 100644 site/src/pages/preferences/ssh-keys.tsx diff --git a/site/src/AppRouter.tsx b/site/src/AppRouter.tsx index 43cd52ba83..bbcd2a7fd1 100644 --- a/site/src/AppRouter.tsx +++ b/site/src/AppRouter.tsx @@ -1,12 +1,16 @@ import React from "react" -import { Route, Routes } from "react-router-dom" +import { Navigate, Route, Routes } from "react-router-dom" import { AuthAndNav, RequireAuth } from "./components" +import { PreferencesLayout } from "./components/Preferences/Layout" import { IndexPage } from "./pages" import { NotFoundPage } from "./pages/404" import { CliAuthenticationPage } from "./pages/cli-auth" import { HealthzPage } from "./pages/healthz" import { SignInPage } from "./pages/login" -import { PreferencesPage } from "./pages/preferences" +import { PreferencesAccountPage } from "./pages/preferences/account" +import { PreferencesLinkedAccountsPage } from "./pages/preferences/linked-accounts" +import { PreferencesSecurityPage } from "./pages/preferences/security" +import { PreferencesSSHKeysPage } from "./pages/preferences/ssh-keys" import { TemplatesPage } from "./pages/templates" import { TemplatePage } from "./pages/templates/[organization]/[template]" import { CreateWorkspacePage } from "./pages/templates/[organization]/[template]/create" @@ -68,15 +72,12 @@ export const AppRouter: React.FC = () => ( /> - - - - - } - /> + }> + } /> + } /> + } /> + } /> + } /> {/* Using path="*"" means "match anything", so this route diff --git a/site/src/components/Panel/Panel.stories.tsx b/site/src/components/Panel/Panel.stories.tsx deleted file mode 100644 index 9db07820d9..0000000000 --- a/site/src/components/Panel/Panel.stories.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Story } from "@storybook/react" -import React from "react" -import { Panel, PanelProps } from "./" - -export default { - title: "Page/Panel", - component: Panel, -} - -const Template: Story = (args: PanelProps) => - -export const Example = Template.bind({}) -Example.args = { - title: "Panel title", - activeTab: "oauthSettings", - menuItems: [ - { label: "OAuth Settings", value: "oauthSettings" }, - { label: "Security", value: "oauthSettings", hasChanges: true }, - { label: "Hardware", value: "oauthSettings" }, - ], -} diff --git a/site/src/components/Preferences/Layout.tsx b/site/src/components/Preferences/Layout.tsx new file mode 100644 index 0000000000..fad3dbefe6 --- /dev/null +++ b/site/src/components/Preferences/Layout.tsx @@ -0,0 +1,34 @@ +import Box from "@material-ui/core/Box" +import React from "react" +import { Outlet } from "react-router-dom" +import { AuthAndNav } from "../Page" +import { TabPanel } from "../TabPanel" + +export const Language = { + accountLabel: "Account", + securityLabel: "Security", + sshKeysLabel: "SSH Keys", + linkedAccountsLabel: "Linked Accounts", + preferencesLabel: "Preferences", +} + +const menuItems = [ + { label: Language.accountLabel, path: "/preferences/account" }, + { label: Language.securityLabel, path: "/preferences/security" }, + { label: Language.sshKeysLabel, path: "/preferences/ssh-keys" }, + { label: Language.linkedAccountsLabel, path: "/preferences/linked-accounts" }, +] + +export const PreferencesLayout: React.FC = () => { + return ( + + + + + + + + + + ) +} diff --git a/site/src/components/Sidebar/Sidebar.stories.tsx b/site/src/components/Sidebar/Sidebar.stories.tsx deleted file mode 100644 index 2dc682773d..0000000000 --- a/site/src/components/Sidebar/Sidebar.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Story } from "@storybook/react" -import React from "react" -import { Sidebar, SidebarProps } from "./" - -export default { - title: "Page/Sidebar", - component: Sidebar, -} - -const Template: Story = (args: SidebarProps) => - -export const Example = Template.bind({}) -Example.args = { - activeItem: "oauthSettings", - menuItems: [ - { label: "OAuth Settings", value: "oauthSettings" }, - { label: "Security", value: "security", hasChanges: true }, - { label: "Hardware", value: "hardware" }, - ], -} diff --git a/site/src/components/TabPanel/TabPanel.stories.tsx b/site/src/components/TabPanel/TabPanel.stories.tsx new file mode 100644 index 0000000000..53bae872e4 --- /dev/null +++ b/site/src/components/TabPanel/TabPanel.stories.tsx @@ -0,0 +1,20 @@ +import { Story } from "@storybook/react" +import React from "react" +import { TabPanel, TabPanelProps } from "." + +export default { + title: "TabPanel/TabPanel", + component: TabPanel, +} + +const Template: Story = (args: TabPanelProps) => + +export const Example = Template.bind({}) +Example.args = { + title: "Title", + menuItems: [ + { label: "OAuth Settings", path: "oauthSettings" }, + { label: "Security", path: "oauthSettings", hasChanges: true }, + { label: "Hardware", path: "oauthSettings" }, + ], +} diff --git a/site/src/components/TabPanel/TabSidebar.stories.tsx b/site/src/components/TabPanel/TabSidebar.stories.tsx new file mode 100644 index 0000000000..e83db7a7e4 --- /dev/null +++ b/site/src/components/TabPanel/TabSidebar.stories.tsx @@ -0,0 +1,19 @@ +import { Story } from "@storybook/react" +import React from "react" +import { TabSidebar, TabSidebarProps } from "./TabSidebar" + +export default { + title: "TabPanel/TabSidebar", + component: TabSidebar, +} + +const Template: Story = (args: TabSidebarProps) => + +export const Example = Template.bind({}) +Example.args = { + menuItems: [ + { label: "OAuth Settings", path: "oauthSettings" }, + { label: "Security", path: "security", hasChanges: true }, + { label: "Hardware", path: "hardware" }, + ], +} diff --git a/site/src/components/Sidebar/index.tsx b/site/src/components/TabPanel/TabSidebar.tsx similarity index 67% rename from site/src/components/Sidebar/index.tsx rename to site/src/components/TabPanel/TabSidebar.tsx index 2058621775..598aa69329 100644 --- a/site/src/components/Sidebar/index.tsx +++ b/site/src/components/TabPanel/TabSidebar.tsx @@ -2,41 +2,35 @@ import List from "@material-ui/core/List" import ListItem from "@material-ui/core/ListItem" import { makeStyles } from "@material-ui/core/styles" import React from "react" +import { NavLink } from "react-router-dom" import { combineClasses } from "../../util/combine-classes" -export interface SidebarItem { - value: string +export interface TabSidebarItem { + path: string label: string hasChanges?: boolean } -export interface SidebarProps { - menuItems: SidebarItem[] - activeItem?: string - onSelect?: (value: string) => void +export interface TabSidebarProps { + menuItems: TabSidebarItem[] } -export const Sidebar: React.FC = ({ menuItems, activeItem, onSelect }) => { +export const TabSidebar: React.FC = ({ menuItems }) => { const styles = useStyles() return ( {menuItems.map(({ hasChanges, ...tab }) => { - const isActive = activeItem === tab.value return ( - onSelect(tab.value) : undefined} - className={styles.menuItem} - disableRipple - focusRipple={false} - component="li" - > - - {hasChanges ? `${tab.label}*` : tab.label} - - + + {({ isActive }) => ( + + + {hasChanges ? `${tab.label}*` : tab.label} + + + )} + ) })} @@ -49,6 +43,10 @@ const useStyles = makeStyles((theme) => ({ marginTop: theme.spacing(5), }, + link: { + textDecoration: "none", + }, + menuItem: { letterSpacing: -theme.spacing(0.0375), padding: 0, diff --git a/site/src/components/Panel/index.tsx b/site/src/components/TabPanel/index.tsx similarity index 84% rename from site/src/components/Panel/index.tsx rename to site/src/components/TabPanel/index.tsx index d4294d82fa..7ea9fe8281 100644 --- a/site/src/components/Panel/index.tsx +++ b/site/src/components/TabPanel/index.tsx @@ -1,18 +1,16 @@ import { makeStyles } from "@material-ui/core/styles" import { fade } from "@material-ui/core/styles/colorManipulator" import React from "react" -import { Sidebar, SidebarItem } from "../Sidebar" +import { TabSidebar, TabSidebarItem } from "./TabSidebar" export type AdminMenuItemCallback = (menuItem: string) => void -export interface PanelProps { +export interface TabPanelProps { title: string - menuItems: SidebarItem[] - activeTab: string - onSelect: AdminMenuItemCallback + menuItems: TabSidebarItem[] } -export const Panel: React.FC = ({ children, title, menuItems, activeTab, onSelect }) => { +export const TabPanel: React.FC = ({ children, title, menuItems }) => { const styles = useStyles() return ( @@ -20,7 +18,7 @@ export const Panel: React.FC = ({ children, title, menuItems, active
{title}
- +
{children}
diff --git a/site/src/pages/preferences/account.tsx b/site/src/pages/preferences/account.tsx new file mode 100644 index 0000000000..20cd380c5a --- /dev/null +++ b/site/src/pages/preferences/account.tsx @@ -0,0 +1,11 @@ +import React from "react" +import { Section } from "../../components/Section" + +const Language = { + title: "Account", + description: "Update your display name, email, profile picture, and dotfiles preferences.", +} + +export const PreferencesAccountPage: React.FC = () => { + return
+} diff --git a/site/src/pages/preferences/index.tsx b/site/src/pages/preferences/index.tsx deleted file mode 100644 index 931784b94c..0000000000 --- a/site/src/pages/preferences/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import Box from "@material-ui/core/Box" -import Paper from "@material-ui/core/Paper" -import React from "react" -import { Header } from "../../components/Header" -import { Footer } from "../../components/Page" - -export const PreferencesPage: React.FC = () => { - return ( - -
- Preferences here! -