diff --git a/chronograf/ui/src/dashboards/components/DashboardsPageContents.tsx b/chronograf/ui/src/dashboards/components/DashboardsPageContents.tsx index 79e8c1c02e..2fb29272f1 100644 --- a/chronograf/ui/src/dashboards/components/DashboardsPageContents.tsx +++ b/chronograf/ui/src/dashboards/components/DashboardsPageContents.tsx @@ -1,11 +1,7 @@ import React, {Component, MouseEvent} from 'react' import DashboardsTable from 'src/dashboards/components/DashboardsTable' -import ImportDashboardOverlay from 'src/dashboards/components/ImportDashboardOverlay' -import SearchBar from 'src/shared/components/SearchBar' -import FancyScrollbar from 'src/shared/components/FancyScrollbar' import {ErrorHandling} from 'src/shared/decorators/errors' -import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology' import {Dashboard} from 'src/types/v2' import {Notification} from 'src/types/notifications' @@ -18,132 +14,44 @@ interface Props { dashboard: Dashboard ) => (event: MouseEvent) => void onExportDashboard: (dashboard: Dashboard) => () => void - onImportDashboard: (dashboard: Dashboard) => void notify: (message: Notification) => void -} - -interface State { searchTerm: string - isOverlayVisible: boolean } @ErrorHandling -class DashboardsPageContents extends Component { - constructor(props) { - super(props) - - this.state = { - searchTerm: '', - isOverlayVisible: false, - } - } - +class DashboardsPageContents extends Component { public render() { const { onDeleteDashboard, - onCreateDashboard, onCloneDashboard, onExportDashboard, + onCreateDashboard, } = this.props return ( - -
-
-
-
- {this.renderPanelHeading} -
- -
-
-
-
-
-
- ) - } - - private get renderPanelHeading(): JSX.Element { - const {onCreateDashboard} = this.props - - return ( - <> -
-

{this.panelTitle}

-
- +
+
+ - -
- {this.renderImportOverlay} - +
) } private get filteredDashboards(): Dashboard[] { - const {dashboards} = this.props - const {searchTerm} = this.state + const {dashboards, searchTerm} = this.props return dashboards.filter(d => d.name.toLowerCase().includes(searchTerm.toLowerCase()) ) } - - private get panelTitle(): string { - const {dashboards} = this.props - - if (dashboards === null) { - return 'Loading Dashboards...' - } else if (dashboards.length === 1) { - return '1 Dashboard' - } - - return `${dashboards.length} Dashboards` - } - - private filterDashboards = (searchTerm: string): void => { - this.setState({searchTerm}) - } - - private handleToggleOverlay = (): void => { - this.setState({isOverlayVisible: !this.state.isOverlayVisible}) - } - - private get renderImportOverlay(): JSX.Element { - const {onImportDashboard, notify} = this.props - const {isOverlayVisible} = this.state - - return ( - - - - ) - } } export default DashboardsPageContents diff --git a/chronograf/ui/src/dashboards/containers/DashboardsPage.tsx b/chronograf/ui/src/dashboards/containers/DashboardsPage.tsx index 8037630cf2..cb5305f2d8 100644 --- a/chronograf/ui/src/dashboards/containers/DashboardsPage.tsx +++ b/chronograf/ui/src/dashboards/containers/DashboardsPage.tsx @@ -7,8 +7,12 @@ import _ from 'lodash' // Components import DashboardsContents from 'src/dashboards/components/DashboardsPageContents' -import PageHeader from 'src/reusable_ui/components/page_layout/PageHeader' +import {Page, PageHeader, PageContents} from 'src/page_layout' +import SearchBar from 'src/shared/components/SearchBar' +import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology' +import ImportDashboardOverlay from 'src/dashboards/components/ImportDashboardOverlay' +// Utils import {getDeep} from 'src/utils/wrappers' // APIs @@ -34,7 +38,9 @@ import {Notification} from 'src/types/notifications' import {DashboardFile, Cell} from 'src/types/v2/dashboards' import {Links, Dashboard} from 'src/types/v2' +// Decorators import {ErrorHandling} from 'src/shared/decorators/errors' + interface Props { router: InjectedRouter links: Links @@ -46,8 +52,22 @@ interface Props { dashboards: Dashboard[] } +interface State { + searchTerm: string + isImportingDashboard: boolean +} + @ErrorHandling -class DashboardsPage extends PureComponent { +class DashboardsPage extends PureComponent { + constructor(props: Props) { + super(props) + + this.state = { + searchTerm: '', + isImportingDashboard: false, + } + } + public async componentDidMount() { const {handleGetDashboards, dashboards, links} = this.props await handleGetDashboards(links.dashboards) @@ -57,20 +77,48 @@ class DashboardsPage extends PureComponent { public render() { const {dashboards, notify} = this.props + const {searchTerm} = this.state return ( -
- - -
+ <> + + + +

Dashboards

+
+ + + + + +
+ + + +
+ {this.renderImportOverlay} + ) } @@ -156,6 +204,29 @@ class DashboardsPage extends PureComponent { cells: cellsWithDefaultsApplied, }) } + + private filterDashboards = (searchTerm: string): void => { + this.setState({searchTerm}) + } + + private handleToggleOverlay = (): void => { + this.setState({isImportingDashboard: !this.state.isImportingDashboard}) + } + + private get renderImportOverlay(): JSX.Element { + const {notify} = this.props + const {isImportingDashboard} = this.state + + return ( + + + + ) + } } const mstp = state => { diff --git a/chronograf/ui/src/page_layout/PageLayout.scss b/chronograf/ui/src/page_layout/PageLayout.scss new file mode 100644 index 0000000000..faf036e162 --- /dev/null +++ b/chronograf/ui/src/page_layout/PageLayout.scss @@ -0,0 +1,36 @@ +/* + Page Layout Styles + ----------------------------------------------------------------------------- +*/ + +$nav-size: 54px; +$nav-breakpoint: 660px; +$page-header-size: 80px; +$page-max-width: 1300px; +$page-gutter: 54px; +$page-title-size: 21px; +$page-title-weight: 400; + +$sidebar--width: 54px; //delete this later + +.chronograf-root { + display: flex; + flex-direction: column; + align-items: center; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + color: $g17-whisper; + @include gradient-v($g2-kevlar,$g0-obsidian); +} + +@media screen and (min-width: $nav-breakpoint) { + .chronograf-root { + flex-direction: row; + } +} + +@import 'components/Nav'; +@import 'components/Page'; diff --git a/chronograf/ui/src/page_layout/components/Nav.scss b/chronograf/ui/src/page_layout/components/Nav.scss index 0d8aa5257f..6ff83346dc 100644 --- a/chronograf/ui/src/page_layout/components/Nav.scss +++ b/chronograf/ui/src/page_layout/components/Nav.scss @@ -3,18 +3,17 @@ ---------------------------------------------- */ -$sidebar--width: 54px; -$sidebar-menu--gutter: 16px; +$nav--gutter: 16px; -$sidebar-menu--bg: $c-pool; -$sidebar-menu--bg-accent: $c-comet; +$nav--bg: $c-pool; +$nav--bg-accent: $c-comet; .nav { display: flex; flex-direction: column; background-color: $g3-castle; border-radius: 0 $radius $radius 0; - width: $sidebar--width; + width: $nav-size; a:link, a:active, @@ -25,8 +24,8 @@ $sidebar-menu--bg-accent: $c-comet; } .nav--item { - width: $sidebar--width; - height: $sidebar--width; + width: $nav-size; + height: $nav-size; position: relative; } @@ -44,15 +43,15 @@ $sidebar-menu--bg-accent: $c-comet; top: 50%; left: 50%; transform: translate(-50%,-50%); - font-size: $sidebar--width * 0.4222; + font-size: $nav-size * 0.4222; } } .nav--item-menu { position: absolute; top: 0; - left: $sidebar--width; - @include gradient-h($sidebar-menu--bg,$sidebar-menu--bg-accent); + left: $nav-size; + @include gradient-h($nav--bg,$nav--bg-accent); display: none; flex-direction: column; align-items: stretch; @@ -63,11 +62,11 @@ $sidebar-menu--bg-accent: $c-comet; .nav--item-header { display: block; color: $g20-white; - height: $sidebar--width; - line-height: $sidebar--width; + height: $nav-size; + line-height: $nav-size; font-size: 19px; font-weight: 400; - padding: 0px $sidebar-menu--gutter; + padding: 0px $nav--gutter; white-space: nowrap; } @@ -77,7 +76,7 @@ $sidebar-menu--bg-accent: $c-comet; .nav--item-icon { color: $g20-white; - background-color: $sidebar-menu--bg; + background-color: $nav--bg; } .nav--item-menu { @@ -100,7 +99,7 @@ $sidebar-menu--bg-accent: $c-comet; // Active Hover State .nav--item.active:hover { .nav--item-icon { - background-color: $sidebar-menu--bg; + background-color: $nav--bg; text-shadow: 0 0 9px $c-yeti, 0 0 15px $c-hydrogen, diff --git a/chronograf/ui/src/page_layout/components/Page.scss b/chronograf/ui/src/page_layout/components/Page.scss new file mode 100644 index 0000000000..2772188ea0 --- /dev/null +++ b/chronograf/ui/src/page_layout/components/Page.scss @@ -0,0 +1,80 @@ +/* + Page Styles + ----------------------------------------------------------------------------- +*/ + +.page { + width: 100%; + flex: 1 0 calc(100% - #{$nav-size}); + display: flex; + flex-direction: column; + align-items: stretch; +} + +@media screen and (min-width: $nav-breakpoint) { + .page { + width: auto; + height: 100%; + } +} + +.page-header { + height: $page-header-size; + padding: 0 $page-gutter; + display: flex; + justify-content: center; + align-items: center; +} + +.page-header--container { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: nowrap; + width: 100%; + max-width: ($page-max-width - ($page-gutter * 2)); +} + +.page-header.full-width .page-header--container { + max-width: 100%; +} + +.page-header--left, +.page-header--right { + display: flex; + align-items: center; +} + +.page-header--left { + flex: 1 0 0; + justify-content: flex-start; + > * { + margin: 0 4px 0 0; + } +} + +.page-header--right { + justify-content: flex-end; + > * { + margin: 0 0 0 4px !important; + + &:only-child { + margin-right: 0 !important; + } + } +} + +.page--title { + letter-spacing: 0; + text-transform: none; + font-size: $page-title-size; + font-weight: $page-title-weight; + margin: 0; + display: inline-block; + @include no-user-select(); + cursor: default; +} + +.page-contents { + height: calc(100% - #{$page-header-size}) !important; +} \ No newline at end of file diff --git a/chronograf/ui/src/page_layout/components/Page.tsx b/chronograf/ui/src/page_layout/components/Page.tsx new file mode 100644 index 0000000000..4b678bfac9 --- /dev/null +++ b/chronograf/ui/src/page_layout/components/Page.tsx @@ -0,0 +1,20 @@ +// Libraries +import React, {Component} from 'react' + +// Decorators +import {ErrorHandling} from 'src/shared/decorators/errors' + +interface Props { + children: JSX.Element | JSX.Element[] +} + +@ErrorHandling +class Page extends Component { + public render() { + const {children} = this.props + + return
{children}
+ } +} + +export default Page diff --git a/chronograf/ui/src/page_layout/components/PageContents.tsx b/chronograf/ui/src/page_layout/components/PageContents.tsx new file mode 100644 index 0000000000..e62333c91c --- /dev/null +++ b/chronograf/ui/src/page_layout/components/PageContents.tsx @@ -0,0 +1,47 @@ +// Libraries +import React, {Component} from 'react' + +// Components +import FancyScrollbar from 'src/shared/components/FancyScrollbar' + +// Decorators +import {ErrorHandling} from 'src/shared/decorators/errors' + +interface Props { + children: JSX.Element[] | JSX.Element + fullWidth: boolean + scrollable: boolean +} + +@ErrorHandling +class PageContents extends Component { + public render() { + const {scrollable} = this.props + + if (scrollable) { + return ( + + {this.children} + + ) + } + + return
{this.children}
+ } + + private get children(): JSX.Element | JSX.Element[] { + const {fullWidth, children} = this.props + + if (fullWidth) { + return children + } + + return ( +
+
{children}
+
+ ) + } +} + +export default PageContents diff --git a/chronograf/ui/src/page_layout/components/PageHeader.tsx b/chronograf/ui/src/page_layout/components/PageHeader.tsx new file mode 100644 index 0000000000..dccae6cd12 --- /dev/null +++ b/chronograf/ui/src/page_layout/components/PageHeader.tsx @@ -0,0 +1,41 @@ +// Libraries +import React, {Component} from 'react' +import classnames from 'classnames' + +// Components +import PageHeaderLeft from 'src/page_layout/components/PageHeaderLeft' +import PageHeaderRight from 'src/page_layout/components/PageHeaderRight' + +// Decorators +import {ErrorHandling} from 'src/shared/decorators/errors' + +interface Props { + children: JSX.Element[] + fullWidth: boolean +} + +@ErrorHandling +class PageHeader extends Component { + public static Left = PageHeaderLeft + public static Right = PageHeaderRight + + public render() { + const {children} = this.props + + return ( +
+
{children}
+
+ ) + } + + private get className(): string { + const {fullWidth} = this.props + + return classnames('page-header', { + 'full-width': fullWidth, + }) + } +} + +export default PageHeader diff --git a/chronograf/ui/src/page_layout/components/PageHeaderLeft.tsx b/chronograf/ui/src/page_layout/components/PageHeaderLeft.tsx new file mode 100644 index 0000000000..07dd9f1532 --- /dev/null +++ b/chronograf/ui/src/page_layout/components/PageHeaderLeft.tsx @@ -0,0 +1,12 @@ +// Libraries +import React, {SFC} from 'react' + +interface Props { + children: JSX.Element | JSX.Element[] +} + +const PageHeaderLeft: SFC = ({children}) => ( +
{children}
+) + +export default PageHeaderLeft diff --git a/chronograf/ui/src/page_layout/components/PageHeaderRight.tsx b/chronograf/ui/src/page_layout/components/PageHeaderRight.tsx new file mode 100644 index 0000000000..a0ed56a5bc --- /dev/null +++ b/chronograf/ui/src/page_layout/components/PageHeaderRight.tsx @@ -0,0 +1,12 @@ +// Libraries +import React, {SFC} from 'react' + +interface Props { + children?: JSX.Element | JSX.Element[] +} + +const PageHeaderRight: SFC = ({children}) => ( +
{children}
+) + +export default PageHeaderRight diff --git a/chronograf/ui/src/page_layout/index.ts b/chronograf/ui/src/page_layout/index.ts index 84634422f9..53db5960ce 100644 --- a/chronograf/ui/src/page_layout/index.ts +++ b/chronograf/ui/src/page_layout/index.ts @@ -1,2 +1,7 @@ import Nav from 'src/page_layout/containers/Nav' +import Page from 'src/page_layout/components/Page' +import PageHeader from 'src/page_layout/components/PageHeader' +import PageContents from 'src/page_layout/components/PageContents' + +export {Page, PageHeader, PageContents} export default Nav diff --git a/chronograf/ui/src/status/containers/StatusPage.tsx b/chronograf/ui/src/status/containers/StatusPage.tsx index 54630d1c70..980c8d5c89 100644 --- a/chronograf/ui/src/status/containers/StatusPage.tsx +++ b/chronograf/ui/src/status/containers/StatusPage.tsx @@ -2,12 +2,12 @@ import React, {Component} from 'react' // Components -import FancyScrollbar from 'src/shared/components/FancyScrollbar' -import PageHeader from 'src/reusable_ui/components/page_layout/PageHeader' +import {Page, PageHeader, PageContents} from 'src/page_layout' // Types import {Source, Cell} from 'src/types/v2' +// Decorators import {ErrorHandling} from 'src/shared/decorators/errors' interface Props { @@ -21,18 +21,19 @@ interface Props { class StatusPage extends Component { public render() { return ( -
- - + + + +

Status Page

+
+ +
+
{JSON.stringify(this.cells)}
-
-
+ + ) } diff --git a/chronograf/ui/src/style/chronograf.scss b/chronograf/ui/src/style/chronograf.scss index 5644664b05..28b32d5635 100644 --- a/chronograf/ui/src/style/chronograf.scss +++ b/chronograf/ui/src/style/chronograf.scss @@ -22,9 +22,9 @@ @import 'components/code-mirror/theme'; // Layout -@import '../page_layout/components/Nav'; +@import '../page_layout/PageLayout'; + @import 'layout/page'; -@import 'layout/page-header'; @import 'layout/page-subsections'; @import 'layout/overlay-technology'; diff --git a/chronograf/ui/src/style/layout/page-header.scss b/chronograf/ui/src/style/layout/page-header.scss deleted file mode 100644 index 07f64aed64..0000000000 --- a/chronograf/ui/src/style/layout/page-header.scss +++ /dev/null @@ -1,121 +0,0 @@ -/* - Page Header - ------------------------------------------------------------------------------ -*/ -$page-header-size: 19px; -$page-header-weight: 400 !important; - -.page-header { - height: 80px; - width: 100%; - padding: 0 $page-wrapper-padding; - display: flex; - justify-content: center; - align-items: center; -} - -.page-header--container { - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: nowrap; - width: 100%; - max-width: ($page-wrapper-max-width - $page-wrapper-padding - $page-wrapper-padding); -} - -// If specified as a full width page header -.page-header.full-width .page-header--container { - max-width: 100%; -} - -// Left, Center, and Right pieces of the page header -.page-header--left, -.page-header--right { - display: flex; - align-items: center; -} -.page-header--left { - flex: 1 0 0; - justify-content: flex-start; - > * { - margin: 0 4px 0 0; - } -} -.page-header--right { - justify-content: flex-end; - > * { - margin: 0 0 0 4px !important; - - &:only-child { - margin-right: 0 !important; - } - } -} - -// Intended to be a

-.page-header--title { - letter-spacing: 0; - text-transform: none; - font-size: $page-header-size; - font-weight: $page-header-weight; - margin: 0; - display: inline-block; - vertical-align: middle; - @include no-user-select(); - cursor: default; -} - -// Misc styles to be refactors -.page-header--container.page-header__source-page { - justify-content: center; -} -.page-header__col-md-8 { - width: 100%; - display: flex; - align-items: center; - justify-content: space-between; -} -@media screen and (min-width: 992px) { - /* - NOTE: - Breakpoint and % width are based on the bootstrap grid - If the source form column sizing is ever changed, this - will have to be manually updated - */ - .page-header__col-md-8 { - width: 66.66667%; - } -} -.page-header__dismiss { - width: ($chronograf-page-header-height - 20px); - height: ($chronograf-page-header-height - 20px); - position: relative; - - /* Use psuedo elements to render the X */ - &:before, - &:after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 22px; - height: 2px; - border-radius: 1px; - background-color: $g11-sidewalk; - transition: background-color 0.25s ease; - } - &:before { - transform: translate(-50%,-50%) rotate(45deg); - } - &:after { - transform: translate(-50%,-50%) rotate(-45deg); - } - /* Hover State */ - &:hover { - cursor: pointer; - } - &:hover:before, - &:hover:after { - background-color: $g18-cloud; - } -} diff --git a/chronograf/ui/src/style/layout/page.scss b/chronograf/ui/src/style/layout/page.scss index d6265d62d9..e0e9dd578e 100644 --- a/chronograf/ui/src/style/layout/page.scss +++ b/chronograf/ui/src/style/layout/page.scss @@ -6,39 +6,7 @@ $dygraph-legend-z: 500; $dash-ceo-z: $dygraph-legend-z + 10; -.chronograf-root { - display: flex; - align-items: center; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - color: $g17-whisper; - @include gradient-v($g2-kevlar,$g0-obsidian); -} -.page { - height: 100%; - flex: 1 0 calc(100% - 50px); - display: flex; - flex-direction: column; - align-items: stretch; -} - -.page-contents { - height: calc(100% - 80px) !important; - - &:only-child { - top: 0; - height: 100% !important; - } -} - -.template-control-bar.show + .page-contents { - top: $chronograf-page-header-height * 2; - height: calc(100% - #{$chronograf-page-header-height * 2}) !important; -} .container-fluid { margin: 0 auto; padding: ($chronograf-page-header-height / 2) $page-wrapper-padding; @@ -55,29 +23,4 @@ $dash-ceo-z: $dygraph-legend-z + 10; height: 100% !important; .container-fluid {padding: 8px !important;} - .template-control--manage {display: none;} -} - -/* - Dashboard Page - ------------------------------------------------------------------------------ - Using a flex based layout so that the Template Variable Control Bar can - have any height without disrupting the layout -*/ -.page.dashboard-page { - display: flex; - flex-direction: column; - align-items: stretch; - flex-wrap: nowrap; - - .page-header { - position: relative; - } - - .page-contents { - position: relative !important; - flex: 1 0 0; - height: 100% !important; - top: 0; - } } \ No newline at end of file diff --git a/chronograf/ui/src/style/theme/_reset.scss b/chronograf/ui/src/style/theme/_reset.scss index f7905fe3c7..06c598a317 100644 --- a/chronograf/ui/src/style/theme/_reset.scss +++ b/chronograf/ui/src/style/theme/_reset.scss @@ -1,6 +1,8 @@ /* - Setting lowermost styles here + Reset + ----------------------------------------------------------------------------- */ + * { margin: 0; padding: 0; @@ -11,12 +13,10 @@ html, body { background-color: $g0-obsidian; } body { - display: flex; padding: 0; width: 100%; height: 100%; position: absolute; - align-items: stretch; overflow: hidden; > #react-root { @@ -25,9 +25,5 @@ body { position: absolute; top: 0; left: 0; - - .container { - margin-top: 60px; - } } }