Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: Add preferences pages #893

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

Merged
merged 11 commits into from
Apr 7, 2022
23 changes: 12 additions & 11 deletions site/src/AppRouter.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -68,15 +72,12 @@ export const AppRouter: React.FC = () => (
/>
</Route>

<Route path="preferences">
<Route
index
element={
<AuthAndNav>
<PreferencesPage />
</AuthAndNav>
}
/>
<Route path="preferences" element={<PreferencesLayout />}>
<Route index element={<Navigate to="account" />} />
<Route path="account" element={<PreferencesAccountPage />} />
<Route path="security" element={<PreferencesSecurityPage />} />
<Route path="ssh-keys" element={<PreferencesSSHKeysPage />} />
<Route path="linked-accounts" element={<PreferencesLinkedAccountsPage />} />
</Route>

{/* Using path="*"" means "match anything", so this route
Expand Down
21 changes: 0 additions & 21 deletions site/src/components/Panel/Panel.stories.tsx

This file was deleted.

34 changes: 34 additions & 0 deletions site/src/components/Preferences/Layout.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<AuthAndNav>
<Box display="flex" flexDirection="column">
<Box style={{ maxWidth: "1380px", margin: "1em auto" }}>
<TabPanel title={Language.preferencesLabel} menuItems={menuItems}>
<Outlet />
</TabPanel>
</Box>
</Box>
</AuthAndNav>
)
}
20 changes: 0 additions & 20 deletions site/src/components/Sidebar/Sidebar.stories.tsx

This file was deleted.

20 changes: 20 additions & 0 deletions site/src/components/TabPanel/TabPanel.stories.tsx
Original file line number Diff line number Diff line change
@@ -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<TabPanelProps> = (args: TabPanelProps) => <TabPanel {...args} />

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" },
],
}
19 changes: 19 additions & 0 deletions site/src/components/TabPanel/TabSidebar.stories.tsx
Original file line number Diff line number Diff line change
@@ -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<TabSidebarProps> = (args: TabSidebarProps) => <TabSidebar {...args} />

export const Example = Template.bind({})
Example.args = {
menuItems: [
{ label: "OAuth Settings", path: "oauthSettings" },
{ label: "Security", path: "security", hasChanges: true },
{ label: "Hardware", path: "hardware" },
],
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<SidebarProps> = ({ menuItems, activeItem, onSelect }) => {
export const TabSidebar: React.FC<TabSidebarProps> = ({ menuItems }) => {
const styles = useStyles()

return (
<List className={styles.menu}>
{menuItems.map(({ hasChanges, ...tab }) => {
const isActive = activeItem === tab.value
return (
<ListItem
key={tab.value}
button
onClick={onSelect ? () => onSelect(tab.value) : undefined}
className={styles.menuItem}
disableRipple
focusRipple={false}
component="li"
>
<span className={combineClasses({ [styles.menuItemSpan]: true, active: isActive })}>
{hasChanges ? `${tab.label}*` : tab.label}
</span>
</ListItem>
<NavLink to={tab.path} key={tab.path} className={styles.link}>
{({ isActive }) => (
<ListItem button className={styles.menuItem} disableRipple focusRipple={false} component="li">
<span className={combineClasses({ [styles.menuItemSpan]: true, active: isActive })}>
{hasChanges ? `${tab.label}*` : tab.label}
</span>
</ListItem>
)}
</NavLink>
)
})}
</List>
Expand All @@ -49,6 +43,10 @@ const useStyles = makeStyles((theme) => ({
marginTop: theme.spacing(5),
},

link: {
textDecoration: "none",
},

menuItem: {
letterSpacing: -theme.spacing(0.0375),
padding: 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
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<PanelProps> = ({ children, title, menuItems, activeTab, onSelect }) => {
export const TabPanel: React.FC<TabPanelProps> = ({ children, title, menuItems }) => {
const styles = useStyles()

return (
<div className={styles.root}>
<div className={styles.inner}>
<div className={styles.menuPanel}>
<div className={styles.title}>{title}</div>
<Sidebar menuItems={menuItems} activeItem={activeTab} onSelect={onSelect} />
<TabSidebar menuItems={menuItems} />
</div>

<div className={styles.contentPanel}>{children}</div>
Expand Down
11 changes: 11 additions & 0 deletions site/src/pages/preferences/account.tsx
Original file line number Diff line number Diff line change
@@ -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 <Section title={Language.title} description={Language.description} />
}
15 changes: 0 additions & 15 deletions site/src/pages/preferences/index.tsx

This file was deleted.

12 changes: 12 additions & 0 deletions site/src/pages/preferences/linked-accounts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react"
import { Section } from "../../components/Section"

const Language = {
title: "Linked Accounts",
description:
"Linking your Coder account will add your workspace SSH key, allowing you to perform Git actions on all your workspaces.",
}

export const PreferencesLinkedAccountsPage: React.FC = () => {
return <Section title={Language.title} description={Language.description} />
}
11 changes: 11 additions & 0 deletions site/src/pages/preferences/security.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from "react"
import { Section } from "../../components/Section"

const Language = {
title: "Security",
description: "Changing your password will sign you out of your current session.",
}

export const PreferencesSecurityPage: React.FC = () => {
return <Section title={Language.title} description={Language.description} />
}
12 changes: 12 additions & 0 deletions site/src/pages/preferences/ssh-keys.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react"
import { Section } from "../../components/Section"

const Language = {
title: "SSH Keys",
description:
"Coder automatically inserts a private key into every workspace; you can add the corresponding public key to any services (such as Git) that you need access to from your workspace.",
}

export const PreferencesSSHKeysPage: React.FC = () => {
return <Section title={Language.title} description={Language.description} />
}