refactor(ui): implement cloud top nav design (#16470)

* refactor: add stylesheet for cloud nav

* refactor: remove cloud icon from side nav

* refactor: move cloud nav to top of app

* chore: add declaration so PNG files are typed as any when imported

* refactor: modify cloud nav to use specified components

* fix: Remove comment

* refactor: update nav item text

* refactor: do not show logout in sidenav for cloud users

* refactor: add unique class for google tag manager

* chore: update changelog

* refactor: don't render user menu if org isn't available

* chore: add image file for logo

Adds-Binary: ui/src/pageLayout/images/influxdata-logo.png

* chore: prettier and eslint
pull/16494/head
alexpaxton 2020-01-09 17:56:12 -08:00 committed by GitHub
parent ba7502aaf5
commit 63b3a07281
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 182 additions and 81 deletions

View File

@ -1,3 +1,9 @@
## v2.0.0-beta.2 [Unreleased]
### UI Improvements
1. [16203](https://github.com/influxdata/influxdb/pull/16203): Move cloud navigation to top of page instead of within left side navigation
## v2.0.0-beta.1 [2020-01-08]
### Features

View File

@ -647,16 +647,14 @@ describe('DataExplorer', () => {
describe('as a task', () => {
beforeEach(() => {
cy.getByTestID('task--radio-button')
.click()
cy.getByTestID('task--radio-button').click()
})
it('should autoselect the first bucket', () => {
cy.getByTestID('task-options-bucket-dropdown--button').within(() => {
cy.get('span.cf-dropdown--selected')
.then((elem) => {
expect(elem.text()).to.include('defbuck')
})
cy.get('span.cf-dropdown--selected').then(elem => {
expect(elem.text()).to.include('defbuck')
})
})
})
})

1
ui/global.d.ts vendored
View File

@ -2,3 +2,4 @@
// got some globals here that only exist during compilation
//
declare module '*.png'

View File

@ -9,6 +9,8 @@ import TooltipPortal from 'src/portals/TooltipPortal'
import NotesPortal from 'src/portals/NotesPortal'
import Notifications from 'src/shared/components/notifications/Notifications'
import OverlayController from 'src/overlays/components/OverlayController'
import CloudNav from 'src/pageLayout/components/CloudNav'
import CloudOnly from 'src/shared/components/cloud/CloudOnly'
// Types
import {AppState} from 'src/types'
@ -23,14 +25,19 @@ interface OwnProps {
type Props = OwnProps & StateProps
const App: SFC<Props> = ({children, inPresentationMode}) => (
<AppWrapper presentationMode={inPresentationMode}>
<Notifications />
<TooltipPortal />
<NotesPortal />
<OverlayController />
<Nav />
{children}
</AppWrapper>
<>
<CloudOnly>
<CloudNav />
</CloudOnly>
<AppWrapper presentationMode={inPresentationMode}>
<Notifications />
<TooltipPortal />
<NotesPortal />
<OverlayController />
<Nav />
{children}
</AppWrapper>
</>
)
const mstp = (state: AppState): StateProps => {

View File

@ -30,30 +30,26 @@ class AccountNavSubItem extends PureComponent<Props> {
}
return (
<>
<CloudExclude key="feature-flag">
{orgs.length > 1 && (
<NavMenu.SubItem
titleLink={className => (
<div onClick={showOrganizationsView} className={className}>
Switch Organizations
</div>
)}
active={false}
key="switch-orgs"
/>
)}
<CloudExclude key="feature-flag">
{orgs.length > 1 && (
<NavMenu.SubItem
titleLink={className => (
<Link to="/orgs/new" className={className}>
Create Organization
</Link>
<div onClick={showOrganizationsView} className={className}>
Switch Organizations
</div>
)}
active={false}
key="switch-orgs"
/>
</CloudExclude>
)}
<NavMenu.SubItem
titleLink={className => (
<Link to="/orgs/new" className={className}>
Create Organization
</Link>
)}
active={false}
/>
<NavMenu.SubItem
titleLink={className => (
<Link to="/logout" className={className}>
@ -63,7 +59,7 @@ class AccountNavSubItem extends PureComponent<Props> {
active={false}
key="logout"
/>
</>
</CloudExclude>
)
}

View File

@ -0,0 +1,45 @@
/*
CloudNav
------------------------------------------------------------------------------
*/
.cloud-nav {
height: 48px;
}
.cloud-nav--logo {
display: inline-block;
height: 26px;
margin: 2px;
}
.cloud-nav--logo-link {
display: inline-block;
}
.cloud-nav--account {
width: 100%;
padding: 6px 16px 8px 16px;
font-size: 12px;
font-weight: 500;
color: $c-neutrino;
margin: 0;
display: block;
user-select: none;
position: relative;
strong {
font-weight: 900;
color: $g20-white;
}
&:after {
content: '';
position: absolute;
width: 100%;
bottom: 0;
left: 0;
height: $ix-border;
@include gradient-h($c-ocean, $c-amethyst);
}
}

View File

@ -1,63 +1,111 @@
import React, {PureComponent} from 'react'
// Libraries
import React, {FC} from 'react'
import {Link} from 'react-router'
import {connect} from 'react-redux'
// Components
import {FeatureFlag} from 'src/shared/utils/featureFlag'
import {NavMenu, Icon} from '@influxdata/clockface'
import CloudOnly from 'src/shared/components/cloud/CloudOnly'
import {
AppHeader,
PopNav,
Button,
ComponentColor,
FlexBox,
FlexDirection,
ComponentSize,
} from '@influxdata/clockface'
// Constants
import {
CLOUD_URL,
CLOUD_USAGE_PATH,
CLOUD_BILLING_PATH,
CLOUD_SIGNOUT_URL,
} from 'src/shared/constants'
// Types
import {IconFont} from '@influxdata/clockface'
import {AppState, Organization} from 'src/types'
export default class CloudNav extends PureComponent {
render() {
// Images
import Logo from '../images/influxdata-logo.png'
// Selectors
import {getOrg} from 'src/organizations/selectors'
interface StateProps {
org: Organization
}
const CloudNav: FC<StateProps> = ({org}) => {
const usageURL = `${CLOUD_URL}${CLOUD_USAGE_PATH}`
const billingURL = `${CLOUD_URL}${CLOUD_BILLING_PATH}`
const handleUpgradeClick = () => {
window.location.assign(billingURL)
}
if (!org) {
return (
<CloudOnly>
<NavMenu.Item
active={false}
titleLink={className => (
<a className={className} href={this.usageURL}>
Usage
</a>
)}
iconLink={className => (
<a className={className} href={this.usageURL}>
<Icon glyph={IconFont.Cloud} />
</a>
)}
>
<AppHeader className="cloud-nav">
<AppHeader.Logo>
<img className="cloud-nav--logo" alt="InfluxData Logo" src={Logo} />
</AppHeader.Logo>
</AppHeader>
)
}
return (
<AppHeader className="cloud-nav">
<AppHeader.Logo>
<Link to={`/orgs/${org.id}`} className="cloud-nav--logo-link">
<img className="cloud-nav--logo" alt="InfluxData Logo" src={Logo} />
</Link>
</AppHeader.Logo>
<FlexBox direction={FlexDirection.Row} margin={ComponentSize.Medium}>
<Button
color={ComponentColor.Success}
text="Upgrade"
onClick={handleUpgradeClick}
className="upgrade-payg--button"
/>
<PopNav>
<p className="cloud-nav--account">
Logged in as <strong>{org.name}</strong>
</p>
<PopNav.Item
active={false}
titleLink={className => (
<a className={className} href={usageURL}>
Usage
</a>
)}
/>
<FeatureFlag name="cloudBilling">
<NavMenu.SubItem
<PopNav.Item
active={false}
titleLink={className => (
<a className={className} href={this.usageURL}>
Usage
</a>
)}
/>
<NavMenu.SubItem
active={false}
titleLink={className => (
<a className={className} href={this.billingURL}>
<a className={className} href={billingURL}>
Billing
</a>
)}
/>
</FeatureFlag>
</NavMenu.Item>
</CloudOnly>
)
}
private get usageURL(): string {
return `${CLOUD_URL}${CLOUD_USAGE_PATH}`
}
private get billingURL(): string {
return `${CLOUD_URL}${CLOUD_BILLING_PATH}`
}
<PopNav.Item
active={false}
titleLink={className => (
<a className={className} href={CLOUD_SIGNOUT_URL}>
Logout
</a>
)}
/>
</PopNav>
</FlexBox>
</AppHeader>
)
}
const mstp = (state: AppState) => {
const org = getOrg(state)
return {org}
}
export default connect<StateProps>(mstp)(CloudNav)

View File

@ -6,7 +6,6 @@ import {get} from 'lodash'
// Components
import {NavMenu, Icon} from '@influxdata/clockface'
import CloudNav from 'src/pageLayout/components/CloudNav'
import AccountNavSubItem from 'src/pageLayout/components/AccountNavSubItem'
import CloudExclude from 'src/shared/components/cloud/CloudExclude'
import CloudOnly from 'src/shared/components/cloud/CloudOnly'
@ -96,7 +95,7 @@ class SideNav extends PureComponent<Props, State> {
<NavMenu.Item
titleLink={className => (
<Link className={className} to={orgPrefix}>
<CloudOnly>{me.name}</CloudOnly>
<CloudOnly>Getting Started</CloudOnly>
<CloudExclude>{`${me.name} (${orgName})`}</CloudExclude>
</Link>
)}
@ -309,7 +308,6 @@ class SideNav extends PureComponent<Props, State> {
key="profile"
/>
</NavMenu.Item>
<CloudNav />
<NavMenu.Item
titleLink={className => (
<a className={className} href={feedbackLink} target="_blank">

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -81,6 +81,7 @@
@import 'src/me/graphics/DashboardingGraphic.scss';
@import 'src/me/graphics/CollectorGraphic.scss';
@import 'src/pageLayout/components/RenamablePageTitle.scss';
@import 'src/pageLayout/components/CloudNav.scss';
@import 'src/timeMachine/components/SelectorList.scss';
@import 'src/timeMachine/components/Queries.scss';
@import 'src/timeMachine/components/EditorShortcutsTooltip.scss';

View File

@ -125,8 +125,9 @@ class TaskOptionsBucketDropdown extends PureComponent<Props> {
}
const mstp = (state: AppState): StateProps => {
const buckets = getAll<Bucket>(state, ResourceType.Buckets)
.filter((bucket: Bucket): boolean => bucket.type !== 'system')
const buckets = getAll<Bucket>(state, ResourceType.Buckets).filter(
(bucket: Bucket): boolean => bucket.type !== 'system'
)
const status = getStatus(state, ResourceType.Buckets)
return {