Merge pull request #3778 from influxdata/refactor-overlay-technology
Refactor Overlay Technologypull/10616/head
commit
be4b65850c
|
@ -2,7 +2,6 @@ import React, {SFC, ReactChildren} from 'react'
|
|||
|
||||
import SideNav from 'src/side_nav'
|
||||
import Notifications from 'src/shared/components/Notifications'
|
||||
import Overlay from 'src/shared/components/OverlayTechnology'
|
||||
|
||||
interface Props {
|
||||
children: ReactChildren
|
||||
|
@ -10,7 +9,6 @@ interface Props {
|
|||
|
||||
const App: SFC<Props> = ({children}) => (
|
||||
<div className="chronograf-root">
|
||||
<Overlay />
|
||||
<Notifications />
|
||||
<SideNav />
|
||||
{children}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, {Component, MouseEvent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
|
||||
|
@ -8,11 +7,7 @@ import ImportDashboardOverlay from 'src/dashboards/components/ImportDashboardOve
|
|||
import SearchBar from 'src/hosts/components/SearchBar'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {
|
||||
showOverlay as showOverlayAction,
|
||||
ShowOverlayActionCreator,
|
||||
} from 'src/shared/actions/overlayTechnology'
|
||||
import {OverlayContext} from 'src/shared/components/OverlayTechnology'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
|
||||
import {Dashboard} from 'src/types'
|
||||
import {Notification} from 'src/types/notifications'
|
||||
|
@ -27,12 +22,12 @@ interface Props {
|
|||
onExportDashboard: (dashboard: Dashboard) => () => void
|
||||
onImportDashboard: (dashboard: Dashboard) => void
|
||||
notify: (message: Notification) => void
|
||||
showOverlay: ShowOverlayActionCreator
|
||||
dashboardLink: string
|
||||
}
|
||||
|
||||
interface State {
|
||||
searchTerm: string
|
||||
isOverlayVisible: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -42,6 +37,7 @@ class DashboardsPageContents extends Component<Props, State> {
|
|||
|
||||
this.state = {
|
||||
searchTerm: '',
|
||||
isOverlayVisible: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,6 +79,7 @@ class DashboardsPageContents extends Component<Props, State> {
|
|||
const {onCreateDashboard} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="panel-heading">
|
||||
<h2 className="panel-title">{this.panelTitle}</h2>
|
||||
<div className="panel-controls">
|
||||
|
@ -94,7 +91,7 @@ class DashboardsPageContents extends Component<Props, State> {
|
|||
<>
|
||||
<button
|
||||
className="btn btn-sm btn-default"
|
||||
onClick={this.showImportOverlay}
|
||||
onClick={this.handleToggleOverlay}
|
||||
>
|
||||
<span className="icon import" /> Import Dashboard
|
||||
</button>
|
||||
|
@ -108,6 +105,8 @@ class DashboardsPageContents extends Component<Props, State> {
|
|||
</Authorized>
|
||||
</div>
|
||||
</div>
|
||||
{this.renderImportOverlay}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -136,30 +135,24 @@ class DashboardsPageContents extends Component<Props, State> {
|
|||
this.setState({searchTerm})
|
||||
}
|
||||
|
||||
private showImportOverlay = (): void => {
|
||||
const {showOverlay, onImportDashboard, notify} = this.props
|
||||
const options = {
|
||||
dismissOnClickOutside: false,
|
||||
dismissOnEscape: false,
|
||||
private handleToggleOverlay = (): void => {
|
||||
this.setState({isOverlayVisible: !this.state.isOverlayVisible})
|
||||
}
|
||||
|
||||
showOverlay(
|
||||
<OverlayContext.Consumer>
|
||||
{({onDismissOverlay}) => (
|
||||
private get renderImportOverlay(): JSX.Element {
|
||||
const {onImportDashboard, notify} = this.props
|
||||
const {isOverlayVisible} = this.state
|
||||
|
||||
return (
|
||||
<OverlayTechnology visible={isOverlayVisible}>
|
||||
<ImportDashboardOverlay
|
||||
onDismissOverlay={onDismissOverlay}
|
||||
onDismissOverlay={this.handleToggleOverlay}
|
||||
onImportDashboard={onImportDashboard}
|
||||
notify={notify}
|
||||
/>
|
||||
)}
|
||||
</OverlayContext.Consumer>,
|
||||
options
|
||||
</OverlayTechnology>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
showOverlay: showOverlayAction,
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(DashboardsPageContents)
|
||||
export default DashboardsPageContents
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
import Container from 'src/shared/components/overlay/OverlayContainer'
|
||||
import Heading from 'src/shared/components/overlay/OverlayHeading'
|
||||
import Body from 'src/shared/components/overlay/OverlayBody'
|
||||
import Container from 'src/reusable_ui/components/overlays/OverlayContainer'
|
||||
import Heading from 'src/reusable_ui/components/overlays/OverlayHeading'
|
||||
import Body from 'src/reusable_ui/components/overlays/OverlayBody'
|
||||
import DragAndDrop from 'src/shared/components/DragAndDrop'
|
||||
import {notifyDashboardImportFailed} from 'src/shared/copy/notifications'
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import QueryMaker from 'src/data_explorer/components/QueryMaker'
|
|||
import Visualization from 'src/data_explorer/components/Visualization'
|
||||
import WriteDataForm from 'src/data_explorer/components/WriteDataForm'
|
||||
import ResizeContainer from 'src/shared/components/ResizeContainer'
|
||||
import OverlayTechnologies from 'src/shared/components/OverlayTechnologies'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import ManualRefresh from 'src/shared/components/ManualRefresh'
|
||||
import AutoRefreshDropdown from 'src/shared/components/AutoRefreshDropdown'
|
||||
import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown'
|
||||
|
@ -49,7 +49,7 @@ interface Props {
|
|||
}
|
||||
|
||||
interface State {
|
||||
showWriteForm: boolean
|
||||
isWriteFormVisible: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -58,7 +58,7 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
super(props)
|
||||
|
||||
this.state = {
|
||||
showWriteForm: false,
|
||||
isWriteFormVisible: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,12 +101,11 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
queryConfigActions,
|
||||
} = this.props
|
||||
|
||||
const {showWriteForm} = this.state
|
||||
const {isWriteFormVisible} = this.state
|
||||
|
||||
return (
|
||||
<>
|
||||
{showWriteForm ? (
|
||||
<OverlayTechnologies>
|
||||
<OverlayTechnology visible={isWriteFormVisible}>
|
||||
<WriteDataForm
|
||||
source={source}
|
||||
errorThrown={errorThrownAction}
|
||||
|
@ -114,8 +113,7 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
onClose={this.handleCloseWriteData}
|
||||
writeLineProtocol={writeLineProtocol}
|
||||
/>
|
||||
</OverlayTechnologies>
|
||||
) : null}
|
||||
</OverlayTechnology>
|
||||
<PageHeader
|
||||
titleText="Data Explorer"
|
||||
fullWidth={true}
|
||||
|
@ -154,11 +152,11 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleCloseWriteData = (): void => {
|
||||
this.setState({showWriteForm: false})
|
||||
this.setState({isWriteFormVisible: false})
|
||||
}
|
||||
|
||||
private handleOpenWriteData = (): void => {
|
||||
this.setState({showWriteForm: true})
|
||||
this.setState({isWriteFormVisible: true})
|
||||
}
|
||||
|
||||
private handleChooseTimeRange = (timeRange: TimeRange): void => {
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import React, {SFC} from 'react'
|
||||
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
|
||||
interface Props {
|
||||
onShowOverlay: () => void
|
||||
overlay: JSX.Element
|
||||
}
|
||||
|
||||
const EmptyFluxPage: SFC<Props> = ({onShowOverlay, overlay}) => (
|
||||
<div className="page">
|
||||
<PageHeader titleText="Flux Editor" fullWidth={true} />
|
||||
<div className="page-contents">
|
||||
<div className="flux-empty">
|
||||
<p>You do not have a configured Flux source</p>
|
||||
<button className="btn btn-primary btn-md" onClick={onShowOverlay}>
|
||||
Connect to Flux
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{overlay}
|
||||
</div>
|
||||
)
|
||||
|
||||
export default EmptyFluxPage
|
|
@ -1,60 +1,70 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import FluxOverlay from 'src/flux/components/FluxOverlay'
|
||||
import {OverlayContext} from 'src/shared/components/OverlayTechnology'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import {
|
||||
showOverlay,
|
||||
ShowOverlayActionCreator,
|
||||
} from 'src/shared/actions/overlayTechnology'
|
||||
|
||||
import {Service} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
showOverlay: ShowOverlayActionCreator
|
||||
service: Service
|
||||
}
|
||||
|
||||
class FluxHeader extends PureComponent<Props> {
|
||||
interface State {
|
||||
isOverlayVisible: boolean
|
||||
}
|
||||
|
||||
class FluxHeader extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
isOverlayVisible: false,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<>
|
||||
<PageHeader
|
||||
titleText="Flux Editor"
|
||||
fullWidth={true}
|
||||
optionsComponents={this.optionsComponents}
|
||||
/>
|
||||
{this.overlay}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private handleToggleOverlay = (): void => {
|
||||
this.setState({isOverlayVisible: !this.state.isOverlayVisible})
|
||||
}
|
||||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
return (
|
||||
<button onClick={this.overlay} className="btn btn-sm btn-default">
|
||||
<button
|
||||
onClick={this.handleToggleOverlay}
|
||||
className="btn btn-sm btn-default"
|
||||
>
|
||||
Edit Connection
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
private overlay = () => {
|
||||
private get overlay(): JSX.Element {
|
||||
const {service} = this.props
|
||||
const {isOverlayVisible} = this.state
|
||||
|
||||
this.props.showOverlay(
|
||||
<OverlayContext.Consumer>
|
||||
{({onDismissOverlay}) => (
|
||||
return (
|
||||
<OverlayTechnology visible={isOverlayVisible}>
|
||||
<FluxOverlay
|
||||
mode="edit"
|
||||
service={service}
|
||||
onDismiss={onDismissOverlay}
|
||||
onDismiss={this.handleToggleOverlay}
|
||||
/>
|
||||
)}
|
||||
</OverlayContext.Consumer>,
|
||||
{}
|
||||
</OverlayTechnology>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
showOverlay,
|
||||
}
|
||||
|
||||
export default connect(null, mdtp)(FluxHeader)
|
||||
export default FluxHeader
|
||||
|
|
|
@ -3,8 +3,9 @@ import {connect} from 'react-redux'
|
|||
import {WithRouterProps} from 'react-router'
|
||||
|
||||
import {FluxPage} from 'src/flux'
|
||||
import EmptyFluxPage from 'src/flux/components/EmptyFluxPage'
|
||||
import FluxOverlay from 'src/flux/components/FluxOverlay'
|
||||
import {OverlayContext} from 'src/shared/components/OverlayTechnology'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import {Source, Service, Notification} from 'src/types'
|
||||
import {Links} from 'src/types/flux'
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
|
@ -12,26 +13,37 @@ import {
|
|||
updateScript as updateScriptAction,
|
||||
UpdateScript,
|
||||
} from 'src/flux/actions'
|
||||
import * as a from 'src/shared/actions/overlayTechnology'
|
||||
import * as b from 'src/shared/actions/services'
|
||||
import * as actions from 'src/shared/actions/services'
|
||||
|
||||
export const NotificationContext = React.createContext()
|
||||
|
||||
const actions = {...a, ...b}
|
||||
|
||||
interface Props {
|
||||
sources: Source[]
|
||||
services: Service[]
|
||||
children: ReactChildren
|
||||
showOverlay: a.ShowOverlayActionCreator
|
||||
fetchServicesAsync: b.FetchServicesAsync
|
||||
fetchServicesAsync: actions.FetchServicesAsync
|
||||
notify: (message: Notification) => void
|
||||
updateScript: UpdateScript
|
||||
script: string
|
||||
links: Links
|
||||
}
|
||||
|
||||
export class CheckServices extends PureComponent<Props & WithRouterProps> {
|
||||
interface State {
|
||||
isOverlayShown: boolean
|
||||
}
|
||||
|
||||
export class CheckServices extends PureComponent<
|
||||
Props & WithRouterProps,
|
||||
State
|
||||
> {
|
||||
constructor(props: Props & WithRouterProps) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
isOverlayShown: false,
|
||||
}
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const source = this.props.sources.find(
|
||||
s => s.id === this.props.params.sourceID
|
||||
|
@ -44,7 +56,7 @@ export class CheckServices extends PureComponent<Props & WithRouterProps> {
|
|||
await this.props.fetchServicesAsync(source)
|
||||
|
||||
if (!this.props.services.length) {
|
||||
this.overlay()
|
||||
this.setState({isOverlayShown: true})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +64,12 @@ export class CheckServices extends PureComponent<Props & WithRouterProps> {
|
|||
const {services, notify, updateScript, links, script} = this.props
|
||||
|
||||
if (!this.props.services.length) {
|
||||
return null // put loading spinner here
|
||||
return (
|
||||
<EmptyFluxPage
|
||||
onShowOverlay={this.handleShowOverlay}
|
||||
overlay={this.renderOverlay}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -65,6 +82,7 @@ export class CheckServices extends PureComponent<Props & WithRouterProps> {
|
|||
notify={notify}
|
||||
updateScript={updateScript}
|
||||
/>
|
||||
{this.renderOverlay}
|
||||
</NotificationContext.Provider>
|
||||
)
|
||||
}
|
||||
|
@ -75,31 +93,31 @@ export class CheckServices extends PureComponent<Props & WithRouterProps> {
|
|||
return sources.find(s => s.id === params.sourceID)
|
||||
}
|
||||
|
||||
private overlay() {
|
||||
const {showOverlay, services} = this.props
|
||||
private get renderOverlay(): JSX.Element {
|
||||
const {isOverlayShown} = this.state
|
||||
|
||||
if (services.length) {
|
||||
return
|
||||
}
|
||||
|
||||
showOverlay(
|
||||
<OverlayContext.Consumer>
|
||||
{({onDismissOverlay}) => (
|
||||
return (
|
||||
<OverlayTechnology visible={isOverlayShown}>
|
||||
<FluxOverlay
|
||||
mode="new"
|
||||
source={this.source}
|
||||
onDismiss={onDismissOverlay}
|
||||
onDismiss={this.handleDismissOverlay}
|
||||
/>
|
||||
)}
|
||||
</OverlayContext.Consumer>,
|
||||
{}
|
||||
</OverlayTechnology>
|
||||
)
|
||||
}
|
||||
|
||||
private handleShowOverlay = (): void => {
|
||||
this.setState({isOverlayShown: true})
|
||||
}
|
||||
|
||||
private handleDismissOverlay = (): void => {
|
||||
this.setState({isOverlayShown: false})
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
fetchServicesAsync: actions.fetchServicesAsync,
|
||||
showOverlay: actions.showOverlay,
|
||||
updateScript: updateScriptAction,
|
||||
notify: notifyAction,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, {PureComponent, ReactChildren} from 'react'
|
||||
|
||||
interface Props {
|
||||
children?: ReactChildren
|
||||
children?: ReactChildren | JSX.Element
|
||||
title: string
|
||||
onDismiss?: () => void
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
import React, {Component} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
children: JSX.Element
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
interface State {
|
||||
showChildren: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class OverlayTechnology extends Component<Props, State> {
|
||||
public static getDerivedStateFromProps(props) {
|
||||
if (props.visible) {
|
||||
return {showChildren: true}
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
private animationTimer: number
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
showChildren: false,
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps) {
|
||||
if (prevProps.visible && !this.props.visible) {
|
||||
clearTimeout(this.animationTimer)
|
||||
this.animationTimer = window.setTimeout(this.hideChildren, 300)
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div className={this.overlayClass}>
|
||||
{this.childContainer}
|
||||
<div className="overlay--mask" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get childContainer(): JSX.Element {
|
||||
const {children} = this.props
|
||||
const {showChildren} = this.state
|
||||
|
||||
if (showChildren) {
|
||||
return (
|
||||
<div className="overlay--dialog" data-test="overlay-children">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <div className="overlay--dialog" data-test="overlay-children" />
|
||||
}
|
||||
|
||||
private get overlayClass(): string {
|
||||
const {visible} = this.props
|
||||
|
||||
return classnames('overlay-tech', {show: visible})
|
||||
}
|
||||
|
||||
private hideChildren = (): void => {
|
||||
this.setState({showChildren: false})
|
||||
}
|
||||
}
|
||||
|
||||
export default OverlayTechnology
|
|
@ -1,34 +0,0 @@
|
|||
import {ReactElement} from 'react'
|
||||
|
||||
type OverlayNodeType = ReactElement<any>
|
||||
|
||||
interface Options {
|
||||
dismissOnClickOutside?: boolean
|
||||
dismissOnEscape?: boolean
|
||||
transitionTime?: number
|
||||
}
|
||||
|
||||
export type ShowOverlayActionCreator = (
|
||||
OverlayNode: OverlayNodeType,
|
||||
options: Options
|
||||
) => ShowOverlayAction
|
||||
|
||||
interface ShowOverlayAction {
|
||||
type: 'SHOW_OVERLAY'
|
||||
payload: {
|
||||
OverlayNode
|
||||
options
|
||||
}
|
||||
}
|
||||
|
||||
export const showOverlay = (
|
||||
OverlayNode: OverlayNodeType,
|
||||
options: Options
|
||||
): ShowOverlayAction => ({
|
||||
type: 'SHOW_OVERLAY',
|
||||
payload: {OverlayNode, options},
|
||||
})
|
||||
|
||||
export const dismissOverlay = () => ({
|
||||
type: 'DISMISS_OVERLAY',
|
||||
})
|
|
@ -1,104 +0,0 @@
|
|||
import React, {PureComponent, Component} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {dismissOverlay} from 'src/shared/actions/overlayTechnology'
|
||||
|
||||
interface Props {
|
||||
OverlayNode?: Component<any>
|
||||
dismissOnClickOutside?: boolean
|
||||
dismissOnEscape?: boolean
|
||||
transitionTime?: number
|
||||
handleDismissOverlay: () => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
export const OverlayContext = React.createContext()
|
||||
|
||||
@ErrorHandling
|
||||
class Overlay extends PureComponent<Props, State> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
dismissOnClickOutside: false,
|
||||
dismissOnEscape: false,
|
||||
transitionTime: 300,
|
||||
}
|
||||
|
||||
private animationTimer: number
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
visible: false,
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps) {
|
||||
if (prevProps.OverlayNode === null && this.props.OverlayNode) {
|
||||
return this.setState({visible: true})
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {OverlayNode} = this.props
|
||||
|
||||
return (
|
||||
<OverlayContext.Provider
|
||||
value={{
|
||||
onDismissOverlay: this.handleAnimateDismiss,
|
||||
}}
|
||||
>
|
||||
<div className={this.overlayClass}>
|
||||
<div className="overlay--dialog">{OverlayNode}</div>
|
||||
<div className="overlay--mask" onClick={this.handleClickOutside} />
|
||||
</div>
|
||||
</OverlayContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
private get overlayClass(): string {
|
||||
const {visible} = this.state
|
||||
return `overlay-tech ${visible ? 'show' : ''}`
|
||||
}
|
||||
|
||||
public handleClickOutside = () => {
|
||||
const {handleDismissOverlay, dismissOnClickOutside} = this.props
|
||||
|
||||
if (dismissOnClickOutside) {
|
||||
handleDismissOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
public handleAnimateDismiss = () => {
|
||||
const {transitionTime} = this.props
|
||||
this.setState({visible: false})
|
||||
this.animationTimer = window.setTimeout(this.handleDismiss, transitionTime)
|
||||
}
|
||||
|
||||
public handleDismiss = () => {
|
||||
const {handleDismissOverlay} = this.props
|
||||
handleDismissOverlay()
|
||||
clearTimeout(this.animationTimer)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({
|
||||
overlayTechnology: {
|
||||
OverlayNode,
|
||||
options: {dismissOnClickOutside, dismissOnEscape, transitionTime},
|
||||
},
|
||||
}) => ({
|
||||
OverlayNode,
|
||||
dismissOnClickOutside,
|
||||
dismissOnEscape,
|
||||
transitionTime,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = {
|
||||
handleDismissOverlay: dismissOverlay,
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Overlay)
|
|
@ -1,12 +0,0 @@
|
|||
import React, {SFC} from 'react'
|
||||
|
||||
const SimpleOverlayTechnology: SFC = ({children}) => {
|
||||
return (
|
||||
<div className="overlay-tech show">
|
||||
<div className="overlay--dialog">{children}</div>
|
||||
<div className="overlay--mask" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SimpleOverlayTechnology
|
|
@ -1,29 +0,0 @@
|
|||
const initialState = {
|
||||
options: {
|
||||
dismissOnClickOutside: false,
|
||||
dismissOnEscape: false,
|
||||
transitionTime: 300,
|
||||
},
|
||||
OverlayNode: null,
|
||||
}
|
||||
|
||||
export default function overlayTechnology(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case 'SHOW_OVERLAY': {
|
||||
const {OverlayNode, options} = action.payload
|
||||
|
||||
return {...state, OverlayNode, options}
|
||||
}
|
||||
|
||||
case 'DISMISS_OVERLAY': {
|
||||
const {options} = initialState
|
||||
return {
|
||||
...state,
|
||||
OverlayNode: null,
|
||||
options,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
|
@ -14,7 +14,6 @@ import adminReducers from 'src/admin/reducers'
|
|||
import kapacitorReducers from 'src/kapacitor/reducers'
|
||||
import dashboardUI from 'src/dashboards/reducers/ui'
|
||||
import cellEditorOverlay from 'src/dashboards/reducers/cellEditorOverlay'
|
||||
import overlayTechnology from 'src/shared/reducers/overlayTechnology'
|
||||
import dashTimeV1 from 'src/dashboards/reducers/dashTimeV1'
|
||||
import persistStateEnhancer from './persistStateEnhancer'
|
||||
import servicesReducer from 'src/shared/reducers/services'
|
||||
|
@ -28,7 +27,6 @@ const rootReducer = combineReducers({
|
|||
...adminReducers,
|
||||
dashboardUI,
|
||||
cellEditorOverlay,
|
||||
overlayTechnology,
|
||||
dashTimeV1,
|
||||
logs: logsReducer,
|
||||
routing: routerReducer,
|
||||
|
|
|
@ -1,85 +1,29 @@
|
|||
$padding: 20px 30px;
|
||||
|
||||
.edit-temp-var {
|
||||
margin: 0 auto;
|
||||
width: 650px;
|
||||
}
|
||||
|
||||
.edit-temp-var--header {
|
||||
background-color: $g0-obsidian;
|
||||
padding: $padding;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.edit-temp-var--header > h1 {
|
||||
color: #eeeff2;
|
||||
letter-spacing: 0;
|
||||
font-size: 19px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.edit-temp-var--header-controls > button {
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.edit-temp-var--body {
|
||||
@include gradient-v($g3-castle, $g1-raven);
|
||||
padding: $padding;
|
||||
|
||||
.delete {
|
||||
margin: 20px auto 10px auto;
|
||||
width: 90px;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-temp-var--body-row {
|
||||
display: flex;
|
||||
|
||||
.name {
|
||||
flex: 1 1 50%;
|
||||
padding-right: 10px;
|
||||
|
||||
input {
|
||||
color: $c-potassium;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.template-type {
|
||||
flex: 1 1 50%;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-toggle, .dropdown-placeholder {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.temp-builder {
|
||||
width: 100%;
|
||||
}
|
||||
/*
|
||||
Create / Edit Template Variable Overlay
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
.temp-builder--mq-controls {
|
||||
background: $g3-castle;
|
||||
border-radius: $radius-small;
|
||||
display: flex;
|
||||
padding: 10px 10px 0 10px;
|
||||
padding: 2px 10px;
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: 10px;
|
||||
&:first-of-type {
|
||||
padding-top: 10px;
|
||||
border-top-left-radius: $radius;
|
||||
border-top-right-radius: $radius;
|
||||
}
|
||||
|
||||
> .temp-builder--mq-text, > .dropdown, .dropdown-placeholder {
|
||||
margin-right: 5px;
|
||||
&:last-of-type {
|
||||
padding-bottom: 10px;
|
||||
border-bottom-left-radius: $radius;
|
||||
border-bottom-right-radius: $radius;
|
||||
}
|
||||
|
||||
> .temp-builder--mq-text,
|
||||
> .dropdown,
|
||||
.dropdown-placeholder {
|
||||
margin-right: 4px;
|
||||
flex-grow: 1;
|
||||
|
||||
&:last-child {
|
||||
|
@ -92,18 +36,16 @@ $padding: 20px 30px;
|
|||
@include no-user-select();
|
||||
background-color: $g5-pepper;
|
||||
border-radius: $radius-small;
|
||||
padding: 8px;
|
||||
padding: 0 8px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
white-space: nowrap;
|
||||
color: $c-pool;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-family: $code-font;
|
||||
}
|
||||
|
||||
.temp-builder .temp-builder-results {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
color: $g19-ghost;
|
||||
|
@ -118,18 +60,21 @@ $padding: 20px 30px;
|
|||
}
|
||||
}
|
||||
|
||||
.temp-builder-results > p {
|
||||
.temp-builder--validation {
|
||||
@include no-user-select();
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
color: $g19-ghost;
|
||||
margin: 15px 0;
|
||||
font-weight: 500;
|
||||
color: $g13-mist;
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
&.error {
|
||||
color: $c-fire;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
color: $c-pineapple;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
|
@ -137,24 +82,34 @@ $padding: 20px 30px;
|
|||
}
|
||||
|
||||
> strong {
|
||||
color: $c-potassium;
|
||||
color: $c-comet;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.temp-builder-results--list {
|
||||
.temp-builder--results {
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.temp-builder--results-list {
|
||||
max-height: 250px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
.temp-builder--results-item {
|
||||
@include no-user-select();
|
||||
background-color: $g3-castle;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: $radius-small;
|
||||
border-radius: $radius;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
color: $g19-ghost;
|
||||
font-weight: bold;
|
||||
color: $g13-mist;
|
||||
font-weight: 600;
|
||||
list-style: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -551,12 +551,6 @@ $rule-builder--radius-lg: 5px;
|
|||
padding-bottom: $rule-builder--padding-lg;
|
||||
}
|
||||
}
|
||||
.endpoint-tab--parameters .faux-form {
|
||||
margin-left: -6px;
|
||||
margin-right: -6px;
|
||||
width: calc(100% + 12px);
|
||||
display: inline-block;
|
||||
}
|
||||
.endpoint-tab--parameters--empty {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
|
@ -9,3 +9,20 @@
|
|||
@import '../components/time-machine/flux-explorer';
|
||||
@import '../components/time-machine/visualization';
|
||||
@import '../components/time-machine/add-func-button';
|
||||
|
||||
// Flux Page Empty state
|
||||
.flux-empty {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
> p {
|
||||
color: $g11-sidewalk;
|
||||
font-size: 16px;
|
||||
@include no-user-select();
|
||||
}
|
||||
}
|
|
@ -423,3 +423,42 @@ button.btn-link-alert {
|
|||
$c-thunder
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
Buttons Groups
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
.btn-group--left,
|
||||
.btn-group--center,
|
||||
.btn-group--right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-group--left > .btn {
|
||||
margin-right: 4px;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group--center > .btn {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group--right > .btn {
|
||||
margin-left: 4px;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ $grid--col-12: 100%;
|
|||
}
|
||||
|
||||
.form-group-submit {
|
||||
margin-top: 30px;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.col {
|
||||
|
@ -220,3 +220,68 @@ $grid--col-12: 100%;
|
|||
&-11 { margin-left: $grid--col-11; }
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapp form sets to ensure proper spacing
|
||||
// ----------------------------------------------------------------------------
|
||||
div.faux-form {
|
||||
width: calc(100% + 12px);
|
||||
margin-left: -6px;
|
||||
margin-right: -6px;
|
||||
display: inline-block;
|
||||
|
||||
.form-group.col-xs-1,
|
||||
.form-group.col-xs-2,
|
||||
.form-group.col-xs-3,
|
||||
.form-group.col-xs-4,
|
||||
.form-group.col-xs-5,
|
||||
.form-group.col-xs-6,
|
||||
.form-group.col-xs-7,
|
||||
.form-group.col-xs-8,
|
||||
.form-group.col-xs-9,
|
||||
.form-group.col-xs-10,
|
||||
.form-group.col-xs-11,
|
||||
.form-group.col-xs-12,
|
||||
.form-group.col-sm-1,
|
||||
.form-group.col-sm-2,
|
||||
.form-group.col-sm-3,
|
||||
.form-group.col-sm-4,
|
||||
.form-group.col-sm-5,
|
||||
.form-group.col-sm-6,
|
||||
.form-group.col-sm-7,
|
||||
.form-group.col-sm-8,
|
||||
.form-group.col-sm-9,
|
||||
.form-group.col-sm-10,
|
||||
.form-group.col-sm-11,
|
||||
.form-group.col-sm-12,
|
||||
.form-group.col-md-1,
|
||||
.form-group.col-md-2,
|
||||
.form-group.col-md-3,
|
||||
.form-group.col-md-4,
|
||||
.form-group.col-md-5,
|
||||
.form-group.col-md-6,
|
||||
.form-group.col-md-7,
|
||||
.form-group.col-md-8,
|
||||
.form-group.col-md-9,
|
||||
.form-group.col-md-10,
|
||||
.form-group.col-md-11,
|
||||
.form-group.col-md-12,
|
||||
.form-group.col-lg-1,
|
||||
.form-group.col-lg-2,
|
||||
.form-group.col-lg-3,
|
||||
.form-group.col-lg-4,
|
||||
.form-group.col-lg-5,
|
||||
.form-group.col-lg-6,
|
||||
.form-group.col-lg-7,
|
||||
.form-group.col-lg-8,
|
||||
.form-group.col-lg-9,
|
||||
.form-group.col-lg-10,
|
||||
.form-group.col-lg-11,
|
||||
.form-group.col-lg-12 {
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
> *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -484,65 +484,6 @@ $dash-editable-header-padding: 7px;
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Fake form padding without <form>
|
||||
|
||||
*/
|
||||
|
||||
div.faux-form {
|
||||
.form-group.col-xs-1,
|
||||
.form-group.col-xs-2,
|
||||
.form-group.col-xs-3,
|
||||
.form-group.col-xs-4,
|
||||
.form-group.col-xs-5,
|
||||
.form-group.col-xs-6,
|
||||
.form-group.col-xs-7,
|
||||
.form-group.col-xs-8,
|
||||
.form-group.col-xs-9,
|
||||
.form-group.col-xs-10,
|
||||
.form-group.col-xs-11,
|
||||
.form-group.col-xs-12,
|
||||
.form-group.col-sm-1,
|
||||
.form-group.col-sm-2,
|
||||
.form-group.col-sm-3,
|
||||
.form-group.col-sm-4,
|
||||
.form-group.col-sm-5,
|
||||
.form-group.col-sm-6,
|
||||
.form-group.col-sm-7,
|
||||
.form-group.col-sm-8,
|
||||
.form-group.col-sm-9,
|
||||
.form-group.col-sm-10,
|
||||
.form-group.col-sm-11,
|
||||
.form-group.col-sm-12,
|
||||
.form-group.col-md-1,
|
||||
.form-group.col-md-2,
|
||||
.form-group.col-md-3,
|
||||
.form-group.col-md-4,
|
||||
.form-group.col-md-5,
|
||||
.form-group.col-md-6,
|
||||
.form-group.col-md-7,
|
||||
.form-group.col-md-8,
|
||||
.form-group.col-md-9,
|
||||
.form-group.col-md-10,
|
||||
.form-group.col-md-11,
|
||||
.form-group.col-md-12,
|
||||
.form-group.col-lg-1,
|
||||
.form-group.col-lg-2,
|
||||
.form-group.col-lg-3,
|
||||
.form-group.col-lg-4,
|
||||
.form-group.col-lg-5,
|
||||
.form-group.col-lg-6,
|
||||
.form-group.col-lg-7,
|
||||
.form-group.col-lg-8,
|
||||
.form-group.col-lg-9,
|
||||
.form-group.col-lg-10,
|
||||
.form-group.col-lg-11,
|
||||
.form-group.col-lg-12 {
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Stretch to fit Dropdowns
|
||||
-----------------------------------------------------------------------------
|
||||
|
|
|
@ -28,20 +28,20 @@ class CSVTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
|
|||
const pluralizer = templateValues.length === 1 ? '' : 's'
|
||||
|
||||
return (
|
||||
<div className="temp-builder csv-temp-builder">
|
||||
<div className="form-group">
|
||||
<>
|
||||
<div className="form-group col-xs-12">
|
||||
<label>Comma Separated Values</label>
|
||||
<div className="temp-builder--mq-controls">
|
||||
<textarea
|
||||
className="form-control"
|
||||
className="form-control input-sm"
|
||||
value={templateValuesString}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="temp-builder-results">
|
||||
<p>
|
||||
<div className="form-group col-xs-12 temp-builder--results">
|
||||
<p className="temp-builder--validation">
|
||||
CSV contains <strong>{templateValues.length}</strong> value{
|
||||
pluralizer
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class CSVTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
|
|||
<TemplatePreviewList items={templateValues} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ class DatabasesTemplateBuilder extends PureComponent<
|
|||
const {databases, databasesStatus} = this.state
|
||||
|
||||
return (
|
||||
<div className="temp-builder databases-temp-builder">
|
||||
<div className="form-group">
|
||||
<>
|
||||
<div className="form-group col-xs-12">
|
||||
<label>Meta Query</label>
|
||||
<div className="temp-builder--mq-controls">
|
||||
<div className="temp-builder--mq-text">SHOW DATABASES</div>
|
||||
|
@ -49,7 +49,7 @@ class DatabasesTemplateBuilder extends PureComponent<
|
|||
items={databases}
|
||||
loadingStatus={databasesStatus}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -77,8 +77,8 @@ class KeysTemplateBuilder extends PureComponent<Props, State> {
|
|||
} = this.state
|
||||
|
||||
return (
|
||||
<div className="temp-builder measurements-temp-builder">
|
||||
<div className="form-group">
|
||||
<>
|
||||
<div className="form-group col-xs-12">
|
||||
<label>Meta Query</label>
|
||||
<div className="temp-builder--mq-controls">
|
||||
<div className="temp-builder--mq-text">{queryPrefix}</div>
|
||||
|
@ -87,7 +87,8 @@ class KeysTemplateBuilder extends PureComponent<Props, State> {
|
|||
items={databases.map(text => ({text}))}
|
||||
onChoose={this.handleChooseDatabaseDropdown}
|
||||
selected={selectedDatabase}
|
||||
buttonSize=""
|
||||
buttonSize="btn-sm"
|
||||
className="dropdown-stretch"
|
||||
/>
|
||||
</DropdownLoadingPlaceholder>
|
||||
<div className="temp-builder--mq-text">FROM</div>
|
||||
|
@ -96,13 +97,14 @@ class KeysTemplateBuilder extends PureComponent<Props, State> {
|
|||
items={measurements.map(text => ({text}))}
|
||||
onChoose={this.handleChooseMeasurementDropdown}
|
||||
selected={selectedMeasurement}
|
||||
buttonSize=""
|
||||
buttonSize="btn-sm"
|
||||
className="dropdown-stretch"
|
||||
/>
|
||||
</DropdownLoadingPlaceholder>
|
||||
</div>
|
||||
</div>
|
||||
<TemplateMetaQueryPreview items={keys} loadingStatus={keysStatus} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,8 @@ class MeasurementsTemplateBuilder extends PureComponent<
|
|||
} = this.state
|
||||
|
||||
return (
|
||||
<div className="temp-builder measurements-temp-builder">
|
||||
<div className="form-group">
|
||||
<>
|
||||
<div className="form-group col-xs-12">
|
||||
<label>Meta Query</label>
|
||||
<div className="temp-builder--mq-controls">
|
||||
<div className="temp-builder--mq-text">SHOW MEASUREMENTS ON</div>
|
||||
|
@ -67,7 +67,8 @@ class MeasurementsTemplateBuilder extends PureComponent<
|
|||
items={databases.map(text => ({text}))}
|
||||
onChoose={this.handleChooseDatabaseDropdown}
|
||||
selected={selectedDatabase}
|
||||
buttonSize=""
|
||||
buttonSize="btn-sm"
|
||||
className="dropdown-stretch"
|
||||
/>
|
||||
</DropdownLoadingPlaceholder>
|
||||
</div>
|
||||
|
@ -76,7 +77,7 @@ class MeasurementsTemplateBuilder extends PureComponent<
|
|||
items={measurements}
|
||||
loadingStatus={measurementsStatus}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -58,12 +58,12 @@ class CustomMetaQueryTemplateBuilder extends PureComponent<
|
|||
const {metaQueryInput} = this.state
|
||||
|
||||
return (
|
||||
<div className="temp-builder csv-temp-builder">
|
||||
<div className="form-group">
|
||||
<>
|
||||
<div className="form-group col-xs-12">
|
||||
<label>Meta Query</label>
|
||||
<div className="temp-builder--mq-controls">
|
||||
<textarea
|
||||
className="form-control"
|
||||
className="form-control input-sm"
|
||||
value={metaQueryInput}
|
||||
onChange={this.handleMetaQueryInputChange}
|
||||
onBlur={this.handleMetaQueryChange}
|
||||
|
@ -71,7 +71,7 @@ class CustomMetaQueryTemplateBuilder extends PureComponent<
|
|||
</div>
|
||||
</div>
|
||||
{this.renderResults()}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,10 @@ class CustomMetaQueryTemplateBuilder extends PureComponent<
|
|||
|
||||
if (this.showInvalidMetaQueryMessage) {
|
||||
return (
|
||||
<div className="temp-builder-results">
|
||||
<p className="error">Meta Query is not valid.</p>
|
||||
<div className="form-group col-xs-12 temp-builder--results">
|
||||
<p className="temp-builder--validation error">
|
||||
Meta Query is not valid.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -79,8 +79,8 @@ class KeysTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
|
|||
} = this.state
|
||||
|
||||
return (
|
||||
<div className="temp-builder measurements-temp-builder">
|
||||
<div className="form-group">
|
||||
<>
|
||||
<div className="form-group col-xs-12">
|
||||
<label>Meta Query</label>
|
||||
<div className="temp-builder--mq-controls">
|
||||
<div className="temp-builder--mq-text">SHOW TAG VALUES ON</div>
|
||||
|
@ -89,7 +89,8 @@ class KeysTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
|
|||
items={databases.map(text => ({text}))}
|
||||
onChoose={this.handleChooseDatabaseDropdown}
|
||||
selected={selectedDatabase}
|
||||
buttonSize=""
|
||||
buttonSize="btn-sm"
|
||||
className="dropdown-stretch"
|
||||
/>
|
||||
</DropdownLoadingPlaceholder>
|
||||
</div>
|
||||
|
@ -100,7 +101,8 @@ class KeysTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
|
|||
items={measurements.map(text => ({text}))}
|
||||
onChoose={this.handleChooseMeasurementDropdown}
|
||||
selected={selectedMeasurement}
|
||||
buttonSize=""
|
||||
buttonSize="btn-sm"
|
||||
className="dropdown-stretch"
|
||||
/>
|
||||
</DropdownLoadingPlaceholder>
|
||||
<div className="temp-builder--mq-text">WITH KEY</div>
|
||||
|
@ -109,7 +111,8 @@ class KeysTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
|
|||
items={tagKeys.map(text => ({text}))}
|
||||
onChoose={this.handleChooseTagKeyDropdown}
|
||||
selected={selectedTagKey}
|
||||
buttonSize=""
|
||||
buttonSize="btn-sm"
|
||||
className="dropdown-stretch"
|
||||
/>
|
||||
</DropdownLoadingPlaceholder>
|
||||
</div>
|
||||
|
@ -118,7 +121,7 @@ class KeysTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
|
|||
items={tagValues}
|
||||
loadingStatus={tagValuesStatus}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, {Component} from 'react'
|
|||
import classnames from 'classnames'
|
||||
|
||||
import TemplateControlDropdown from 'src/tempVars/components/TemplateControlDropdown'
|
||||
import SimpleOverlayTechnology from 'src/shared/components/SimpleOverlayTechnology'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import TemplateVariableEditor from 'src/tempVars/components/TemplateVariableEditor'
|
||||
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
|
||||
|
@ -64,15 +64,13 @@ class TemplateControlBar extends Component<Props, State> {
|
|||
<strong>Template Variables</strong>
|
||||
</div>
|
||||
)}
|
||||
{isAdding && (
|
||||
<SimpleOverlayTechnology>
|
||||
<OverlayTechnology visible={isAdding}>
|
||||
<TemplateVariableEditor
|
||||
source={source}
|
||||
onCreate={this.handleCreateTemplate}
|
||||
onCancel={this.handleCancelAddVariable}
|
||||
/>
|
||||
</SimpleOverlayTechnology>
|
||||
)}
|
||||
</OverlayTechnology>
|
||||
</div>
|
||||
<Authorized requiredRole={EDITOR_ROLE}>
|
||||
<button
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
import SimpleOverlayTechnology from 'src/shared/components/SimpleOverlayTechnology'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import TemplateVariableEditor from 'src/tempVars/components/TemplateVariableEditor'
|
||||
import {calculateDropdownWidth} from 'src/dashboards/constants/templateControlBar'
|
||||
import Authorized, {isUserAuthorized, EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
|
@ -76,8 +76,7 @@ class TemplateControlDropdown extends PureComponent<Props, State> {
|
|||
/>
|
||||
</label>
|
||||
</Authorized>
|
||||
{isEditing && (
|
||||
<SimpleOverlayTechnology>
|
||||
<OverlayTechnology visible={isEditing}>
|
||||
<TemplateVariableEditor
|
||||
template={template}
|
||||
source={source}
|
||||
|
@ -86,8 +85,7 @@ class TemplateControlDropdown extends PureComponent<Props, State> {
|
|||
onDelete={this.handleDelete}
|
||||
onCancel={this.handleHideSettings}
|
||||
/>
|
||||
</SimpleOverlayTechnology>
|
||||
)}
|
||||
</OverlayTechnology>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,29 +16,33 @@ class TemplateMetaQueryPreview extends PureComponent<Props> {
|
|||
const {items, loadingStatus} = this.props
|
||||
|
||||
if (loadingStatus === RemoteDataState.NotStarted) {
|
||||
return <div className="temp-builder-results" />
|
||||
return null
|
||||
}
|
||||
|
||||
if (loadingStatus === RemoteDataState.Loading) {
|
||||
return (
|
||||
<div className="temp-builder-results">
|
||||
<p className="loading">Loading meta query preview...</p>
|
||||
<div className="form-group col-xs-12 temp-builder--results">
|
||||
<p className="temp-builder--validation loading">
|
||||
Loading Meta Query preview...
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (loadingStatus === RemoteDataState.Error) {
|
||||
return (
|
||||
<div className="temp-builder-results">
|
||||
<p className="error">Meta Query failed to execute</p>
|
||||
<div className="form-group col-xs-12 temp-builder--results">
|
||||
<p className="temp-builder--validation error">
|
||||
Meta Query failed to execute
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (items.length === 0) {
|
||||
return (
|
||||
<div className="temp-builder-results">
|
||||
<p className="warning">
|
||||
<div className="form-group col-xs-12 temp-builder--results">
|
||||
<p className="temp-builder--validation warning">
|
||||
Meta Query is syntactically correct but returned no results
|
||||
</p>
|
||||
</div>
|
||||
|
@ -48,8 +52,8 @@ class TemplateMetaQueryPreview extends PureComponent<Props> {
|
|||
const pluralizer = items.length === 1 ? '' : 's'
|
||||
|
||||
return (
|
||||
<div className="temp-builder-results">
|
||||
<p>
|
||||
<div className="form-group col-xs-12 temp-builder--results">
|
||||
<p className="temp-builder--validation">
|
||||
Meta Query returned <strong>{items.length}</strong> value{pluralizer}
|
||||
</p>
|
||||
{items.length > 0 && <TemplatePreviewList items={items} />}
|
||||
|
|
|
@ -4,8 +4,8 @@ import uuid from 'uuid'
|
|||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
|
||||
const LI_HEIGHT = 35
|
||||
const LI_MARGIN_BOTTOM = 3
|
||||
const LI_HEIGHT = 28
|
||||
const LI_MARGIN_BOTTOM = 2
|
||||
const RESULTS_TO_DISPLAY = 10
|
||||
|
||||
interface Props {
|
||||
|
@ -19,13 +19,14 @@ class TemplatePreviewList extends PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<ul
|
||||
className="temp-builder-results--list"
|
||||
className="temp-builder--results-list"
|
||||
style={{height: `${this.resultsListHeight}px`}}
|
||||
>
|
||||
<FancyScrollbar>
|
||||
<FancyScrollbar autoHide={false}>
|
||||
{items.map(db => {
|
||||
return (
|
||||
<li
|
||||
className="temp-builder--results-item"
|
||||
key={uuid.v4()}
|
||||
style={{
|
||||
height: `${LI_HEIGHT}px`,
|
||||
|
|
|
@ -7,6 +7,9 @@ import React, {
|
|||
import {connect} from 'react-redux'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import OverlayContainer from 'src/reusable_ui/components/overlays/OverlayContainer'
|
||||
import OverlayHeading from 'src/reusable_ui/components/overlays/OverlayHeading'
|
||||
import OverlayBody from 'src/reusable_ui/components/overlays/OverlayBody'
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
import ConfirmButton from 'src/shared/components/ConfirmButton'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
|
@ -63,7 +66,7 @@ const TEMPLATE_BUILDERS = {
|
|||
[TemplateType.MetaQuery]: MetaQueryTemplateBuilder,
|
||||
}
|
||||
|
||||
const formatName = name => `:${name.replace(/:/g, '')}:`
|
||||
const formatName = name => `:${name.replace(/:/g, '').replace(/\s/g, '')}:`
|
||||
|
||||
const DEFAULT_TEMPLATE = DEFAULT_TEMPLATES[TemplateType.Databases]
|
||||
|
||||
|
@ -100,19 +103,18 @@ class TemplateVariableEditor extends PureComponent<Props, State> {
|
|||
const TemplateBuilder = this.templateBuilder
|
||||
|
||||
return (
|
||||
<div className="edit-temp-var">
|
||||
<div className="edit-temp-var--header">
|
||||
<h1>{isNew ? 'Create' : 'Edit'} Template Variable</h1>
|
||||
<div className="edit-temp-var--header-controls">
|
||||
<OverlayContainer maxWidth={650}>
|
||||
<OverlayHeading title={this.title}>
|
||||
<div className="btn-group--right">
|
||||
<button
|
||||
className="btn btn-default"
|
||||
className="btn btn-default btn-sm"
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-success"
|
||||
className="btn btn-success btn-sm"
|
||||
type="button"
|
||||
onClick={this.handleSave}
|
||||
disabled={!this.canSave}
|
||||
|
@ -120,50 +122,72 @@ class TemplateVariableEditor extends PureComponent<Props, State> {
|
|||
{this.saveButtonText}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="edit-temp-var--body">
|
||||
<div className="edit-temp-var--body-row">
|
||||
<div className="form-group name">
|
||||
</OverlayHeading>
|
||||
<OverlayBody>
|
||||
<div className="faux-form">
|
||||
<div className="form-group col-sm-6">
|
||||
<label>Name</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
className="form-control input-sm form-astronaut"
|
||||
value={nextTemplate.tempVar}
|
||||
onChange={this.handleChangeName}
|
||||
onKeyPress={this.handleNameKeyPress}
|
||||
onBlur={this.formatName}
|
||||
spellCheck={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group template-type">
|
||||
<div className="form-group col-sm-6">
|
||||
<label>Type</label>
|
||||
<Dropdown
|
||||
items={TEMPLATE_TYPES_LIST}
|
||||
onChoose={this.handleChooseType}
|
||||
selected={this.dropdownSelection}
|
||||
buttonSize=""
|
||||
buttonSize="btn-sm"
|
||||
className="dropdown-stretch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="edit-temp-var--body-row">
|
||||
<TemplateBuilder
|
||||
template={nextTemplate}
|
||||
source={source}
|
||||
onUpdateTemplate={this.handleUpdateTemplate}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group text-center form-group-submit col-xs-12">
|
||||
<ConfirmButton
|
||||
text={this.isDeleting ? 'Deleting...' : 'Delete'}
|
||||
text={this.confirmText}
|
||||
confirmAction={this.handleDelete}
|
||||
type="btn-danger"
|
||||
size="btn-xs"
|
||||
size="btn-sm"
|
||||
customClass="delete"
|
||||
disabled={isNew || this.isDeleting}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</OverlayBody>
|
||||
</OverlayContainer>
|
||||
)
|
||||
}
|
||||
|
||||
private get confirmText(): string {
|
||||
if (this.isDeleting) {
|
||||
return 'Deleting...'
|
||||
}
|
||||
|
||||
return 'Delete'
|
||||
}
|
||||
|
||||
private get title(): string {
|
||||
const {isNew} = this.state
|
||||
|
||||
let prefix = 'Edit'
|
||||
|
||||
if (isNew) {
|
||||
prefix = 'Create'
|
||||
}
|
||||
|
||||
return `${prefix} Template Variable`
|
||||
}
|
||||
|
||||
private get templateBuilder(): ComponentClass<TemplateBuilderProps> {
|
||||
const {
|
||||
nextTemplate: {type},
|
||||
|
|
|
@ -4,7 +4,7 @@ import {shallow} from 'enzyme'
|
|||
import TemplateControlBar from 'src/tempVars/components/TemplateControlBar'
|
||||
import TemplateControlDropdown from 'src/tempVars/components/TemplateControlDropdown'
|
||||
import TemplateVariableEditor from 'src/tempVars/components/TemplateVariableEditor'
|
||||
import SimpleOverlayTechnology from 'src/shared/components/SimpleOverlayTechnology'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import {source} from 'test/resources'
|
||||
|
||||
import {TemplateType, TemplateValueType} from 'src/types'
|
||||
|
@ -61,14 +61,24 @@ describe('TemplateControlBar', () => {
|
|||
|
||||
it('renders an TemplateVariableEditor overlay when adding a template variable', () => {
|
||||
const props = {...defaultProps}
|
||||
const wrapper = shallow(<TemplateControlBar {...props} />)
|
||||
const wrapper = shallow(<TemplateControlBar {...props} />, {
|
||||
context: {
|
||||
store: {},
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find(SimpleOverlayTechnology)).toHaveLength(0)
|
||||
const children = wrapper
|
||||
.find(OverlayTechnology)
|
||||
.dive()
|
||||
.find("[data-test='overlay-children']")
|
||||
.children()
|
||||
|
||||
expect(children).toHaveLength(0)
|
||||
|
||||
wrapper.find('[data-test="add-template-variable"]').simulate('click')
|
||||
|
||||
const elements = wrapper
|
||||
.find(SimpleOverlayTechnology)
|
||||
.find(OverlayTechnology)
|
||||
.dive()
|
||||
.find(TemplateVariableEditor)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
|
||||
import SimpleOverlayTechnology from 'src/shared/components/SimpleOverlayTechnology'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import TemplateVariableEditor from 'src/tempVars/components/TemplateVariableEditor'
|
||||
import TemplateControlDropdown from 'src/tempVars/components/TemplateControlDropdown'
|
||||
import {source} from 'test/resources'
|
||||
|
@ -33,14 +33,24 @@ const defaultProps = {
|
|||
|
||||
describe('TemplateControlDropdown', () => {
|
||||
it('should show a TemplateVariableEditor overlay when the settings icon is clicked', () => {
|
||||
const wrapper = shallow(<TemplateControlDropdown {...defaultProps} />)
|
||||
const wrapper = shallow(<TemplateControlDropdown {...defaultProps} />, {
|
||||
context: {
|
||||
store: {},
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find(SimpleOverlayTechnology)).toHaveLength(0)
|
||||
const children = wrapper
|
||||
.find(OverlayTechnology)
|
||||
.dive()
|
||||
.find("[data-test='overlay-children']")
|
||||
.children()
|
||||
|
||||
expect(children).toHaveLength(0)
|
||||
|
||||
wrapper.find("[data-test='edit']").simulate('click')
|
||||
|
||||
const elements = wrapper
|
||||
.find(SimpleOverlayTechnology)
|
||||
.find(OverlayTechnology)
|
||||
.dive()
|
||||
.find(TemplateVariableEditor)
|
||||
|
||||
|
|
Loading…
Reference in New Issue