diff --git a/ui/src/side_nav/components/NavItems.js b/ui/src/side_nav/components/NavItems.js
deleted file mode 100644
index b06566cec6..0000000000
--- a/ui/src/side_nav/components/NavItems.js
+++ /dev/null
@@ -1,130 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import {Link} from 'react-router'
-import classnames from 'classnames'
-
-const {bool, node, string} = PropTypes
-
-const NavListItem = React.createClass({
- propTypes: {
- link: string.isRequired,
- children: node,
- location: string,
- useAnchor: bool,
- isExternal: bool,
- },
-
- render() {
- const {link, children, location, useAnchor, isExternal} = this.props
- const isActive = location.startsWith(link)
-
- return useAnchor ? (
-
- {children}
-
- ) : (
-
- {children}
-
- )
- },
-})
-
-const NavHeader = React.createClass({
- propTypes: {
- link: string,
- title: string,
- useAnchor: bool,
- },
- render() {
- const {link, title, useAnchor} = this.props
-
- // Some nav items, such as Logout, need to hit an external link rather
- // than simply route to an internal page. Anchor tags serve that purpose.
- return useAnchor ? (
-
- {title}
-
- ) : (
-
- {title}
-
- )
- },
-})
-
-const NavBlock = React.createClass({
- propTypes: {
- children: node,
- link: string,
- icon: string.isRequired,
- location: string,
- className: string,
- },
-
- render() {
- const {location, className} = this.props
- const isActive = React.Children.toArray(this.props.children).find(child => {
- return location.startsWith(child.props.link) // if location is undefined, this will fail silently
- })
-
- const children = React.Children.map(this.props.children, child => {
- if (child && child.type === NavListItem) {
- return React.cloneElement(child, {location})
- }
-
- return child
- })
-
- return (
-
- {this.renderSquare()}
-
-
- )
- },
-
- renderSquare() {
- const {link, icon} = this.props
-
- if (!link) {
- return (
-
- )
- }
-
- return (
-
-
-
- )
- },
-})
-
-const NavBar = React.createClass({
- propTypes: {
- children: node,
- },
-
- render() {
- const {children} = this.props
-
- return
- },
-})
-
-export {NavBar, NavBlock, NavHeader, NavListItem}
diff --git a/ui/src/side_nav/components/NavItems.tsx b/ui/src/side_nav/components/NavItems.tsx
new file mode 100644
index 0000000000..2d9aeb9650
--- /dev/null
+++ b/ui/src/side_nav/components/NavItems.tsx
@@ -0,0 +1,120 @@
+import React, {PureComponent, SFC, ReactNode, ReactElement} from 'react'
+import {Link} from 'react-router'
+import classnames from 'classnames'
+
+interface NavListItemProps {
+ link?: string
+ location?: string
+ useAnchor?: boolean
+ isExternal?: boolean
+ children?: ReactNode
+}
+
+const NavListItem: SFC = ({
+ link,
+ children,
+ location,
+ useAnchor,
+ isExternal,
+}) => {
+ const isActive = location.startsWith(link)
+ return useAnchor ? (
+
+ {children}
+
+ ) : (
+
+ {children}
+
+ )
+}
+
+interface NavHeaderProps {
+ link?: string
+ title?: string
+ useAnchor?: string
+}
+
+const NavHeader: SFC = ({link, title, useAnchor}) => {
+ // Some nav items, such as Logout, need to hit an external link rather
+ // than simply route to an internal page. Anchor tags serve that purpose.
+ return useAnchor ? (
+
+ {title}
+
+ ) : (
+
+ {title}
+
+ )
+}
+
+interface NavBlockProps {
+ children?: ReactNode
+ link?: string
+ icon: string
+ location?: string
+ className?: string
+ matcher?: string
+}
+
+class NavBlock extends PureComponent {
+ public render() {
+ const {location, className} = this.props
+ const isActive = React.Children.toArray(this.props.children).find(
+ (child: ReactElement) => {
+ return location.startsWith(child.props.link) // if location is undefined, this will fail silently
+ }
+ )
+
+ const children = React.Children.map(
+ this.props.children,
+ (child: ReactElement) => {
+ if (child && child.type === NavListItem) {
+ return React.cloneElement(child, {location})
+ }
+
+ return child
+ }
+ )
+
+ return (
+
+ {this.renderSquare()}
+
+
+ )
+ }
+
+ private renderSquare() {
+ const {link, icon} = this.props
+
+ if (!link) {
+ return (
+
+ )
+ }
+
+ return (
+
+
+
+ )
+ }
+}
+
+export {NavBlock, NavHeader, NavListItem}
diff --git a/ui/src/side_nav/containers/SideNav.tsx b/ui/src/side_nav/containers/SideNav.tsx
index 26fbb2a403..d48d57e827 100644
--- a/ui/src/side_nav/containers/SideNav.tsx
+++ b/ui/src/side_nav/containers/SideNav.tsx
@@ -6,52 +6,13 @@ import Authorized, {ADMIN_ROLE} from 'src/auth/Authorized'
import UserNavBlock from 'src/side_nav/components/UserNavBlock'
import {
- NavBar,
NavBlock,
NavHeader,
NavListItem,
} from 'src/side_nav/components/NavItems'
import {DEFAULT_HOME_PAGE} from 'src/shared/constants'
-
-interface Params {
- sourceID: string
-}
-
-interface Location {
- pathname: string
-}
-
-interface ExternalLink {
- name: string
- url: string
-}
-
-interface ExternalLinks {
- custom: ExternalLink[]
-}
-
-interface Links {
- me?: string
- external?: ExternalLinks
-}
-
-interface Organization {
- id: string
- name: string
-}
-
-interface Role {
- id: string
- name: string
-}
-
-interface Me {
- name: string
- currentOrganization: Organization
- organizations: Organization[]
- role: Role[]
-}
+import {Params, Location, Links, Me} from 'src/types/sideNav'
interface Props {
params: Params
@@ -85,7 +46,7 @@ class SideNav extends PureComponent {
const isDefaultPage = location.split('/').includes(DEFAULT_HOME_PAGE)
return isHidden ? null : (
-
+