Protoboard selection (#4263)
* Add protoboard types * Add new component GridSizer * Remove obsolete CardSelectList component * Update CardSelectCardComponent * import Gridsizer styles * Add Dashboard step to wizard * Remove obsolete type * update Protoboard types to be more specific * Move css import, read selected value existing in state * Use lodash debounce, add defaultl width prop * Add defaut props for checked and disabled, always prevent defaultpull/4269/head
parent
789d3d7f1e
commit
e98973b0ba
|
@ -3,54 +3,12 @@
|
|||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
$card-select--gutter: 4px;
|
||||
|
||||
$card-breakpoint-col-2: 600px;
|
||||
$card-breakpoint-col-3: 700px;
|
||||
$card-breakpoint-col-4: 800px;
|
||||
$card-breakpoint-col-5: 900px;
|
||||
$card-breakpoint-col-6: 1000px;
|
||||
|
||||
.card-select--card-holder {
|
||||
width: 100%;
|
||||
padding-bottom: 100%;
|
||||
float: left;
|
||||
position: relative;
|
||||
|
||||
@media only screen and (min-width: $card-breakpoint-col-2) {
|
||||
width: 50%;
|
||||
padding-bottom: 50%;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: $card-breakpoint-col-3) {
|
||||
width: 33.3333%;
|
||||
padding-bottom: 33.3333%;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: $card-breakpoint-col-4) {
|
||||
width: 25%;
|
||||
padding-bottom: 25%;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: $card-breakpoint-col-5) {
|
||||
width: 20%;
|
||||
padding-bottom: 20%;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: $card-breakpoint-col-6) {
|
||||
width: 16.6667%;
|
||||
padding-bottom: 16.6667%;
|
||||
}
|
||||
}
|
||||
|
||||
.card-select--card {
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
background-color: $g1-raven;
|
||||
border-radius: $radius;
|
||||
border: $ix-border solid transparent;
|
||||
width: calc(100% - #{$card-select--gutter});
|
||||
height: calc(100% - #{$card-select--gutter});
|
||||
margin: $card-select--gutter / 2;
|
||||
position: absolute;
|
||||
transition: border-color .2s ease, background-color .2s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
@ -79,7 +37,7 @@ $card-breakpoint-col-6: 1000px;
|
|||
|
||||
.card-select--image {
|
||||
justify-content: center;
|
||||
width: 60%;
|
||||
max-width: 60%;
|
||||
.card-select--placeholder {
|
||||
color: $ix-text-default;
|
||||
transition: color .2s ease;
|
||||
|
|
|
@ -1,86 +1,64 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Types
|
||||
import {CardSelectCardProps} from 'src/types/cardSelect'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface State {
|
||||
checked: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
name?: string
|
||||
label: string
|
||||
image?: string
|
||||
checked?: boolean
|
||||
disabled?: boolean
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class CardSelectCard extends PureComponent<CardSelectCardProps, State> {
|
||||
public static defaultProps: Partial<CardSelectCardProps> = {
|
||||
class CardSelectCard extends PureComponent<Props> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
checked: false,
|
||||
disabled: false,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
checked: this.props.checked,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {id, label, disabled} = this.props
|
||||
const {checked} = this.state
|
||||
const {id, label, checked, name, disabled} = this.props
|
||||
|
||||
return (
|
||||
<div className="card-select--card-holder">
|
||||
<div
|
||||
data-toggle="card_toggle"
|
||||
onClick={this.toggleChecked}
|
||||
className={classnames('card-select--card', {
|
||||
'card-select--checked': checked,
|
||||
'card-select--disabled': disabled,
|
||||
'card-select--active': !disabled,
|
||||
})}
|
||||
>
|
||||
<label className="card-select--container">
|
||||
<input
|
||||
id={`card_select_${id}`}
|
||||
name={`card_select_${id}`}
|
||||
type="checkbox"
|
||||
value={id}
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<span
|
||||
className={classnames(
|
||||
'card-select--checkmark',
|
||||
'icon',
|
||||
'checkmark',
|
||||
{
|
||||
'card-select--checked': checked,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
<div className="card-select--image">{this.cardImage}</div>
|
||||
<span className="card-select--label">{label}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
data-toggle="card_toggle"
|
||||
onClick={this.handleClick}
|
||||
className={classnames('card-select--card', {
|
||||
'card-select--checked': checked,
|
||||
'card-select--disabled': disabled,
|
||||
'card-select--active': !disabled,
|
||||
})}
|
||||
>
|
||||
<label className="card-select--container">
|
||||
<input
|
||||
id={`card_select_${id}`}
|
||||
name={name}
|
||||
type="checkbox"
|
||||
value={id}
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<span
|
||||
className={classnames(
|
||||
'card-select--checkmark',
|
||||
'icon',
|
||||
'checkmark',
|
||||
{
|
||||
'card-select--checked': checked,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
<div className="card-select--image">{this.cardImage}</div>
|
||||
<span className="card-select--label">{label}</span>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private toggleChecked = e => {
|
||||
const {disabled} = this.props
|
||||
|
||||
if (disabled) {
|
||||
return
|
||||
}
|
||||
|
||||
const {checked} = this.state
|
||||
e.preventDefault()
|
||||
this.setState({
|
||||
checked: !checked,
|
||||
})
|
||||
}
|
||||
|
||||
private get cardImage() {
|
||||
const {image, label} = this.props
|
||||
|
||||
|
@ -90,6 +68,14 @@ class CardSelectCard extends PureComponent<CardSelectCardProps, State> {
|
|||
|
||||
return <span className="card-select--placeholder icon dash-j" />
|
||||
}
|
||||
|
||||
private handleClick = e => {
|
||||
const {onClick, disabled} = this.props
|
||||
e.preventDefault()
|
||||
if (!disabled) {
|
||||
onClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CardSelectCard
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
Card Selector Wrapper
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
.card-select--wrapper {
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card-select--cards {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
import React, {PureComponent, ReactElement} from 'react'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import CardSelectCard from 'src/reusable_ui/components/card_select/CardSelectCard'
|
||||
|
||||
import {CardSelectCardProps} from 'src/types/cardSelect'
|
||||
|
||||
interface Props {
|
||||
children: Array<ReactElement<CardSelectCardProps>>
|
||||
legend: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class CardSelectList extends PureComponent<Props> {
|
||||
public static Card = CardSelectCard
|
||||
|
||||
public render() {
|
||||
const {children, legend} = this.props
|
||||
|
||||
return (
|
||||
<fieldset className="card-select--wrapper">
|
||||
<legend>{legend}</legend>
|
||||
<div className="card-select--cards">{children}</div>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CardSelectList
|
|
@ -10,9 +10,11 @@ describe('Card Select Card', () => {
|
|||
const props = {
|
||||
id: 'card_id',
|
||||
label: 'Card Label',
|
||||
name: undefined,
|
||||
image: undefined,
|
||||
checked: undefined,
|
||||
disabled: undefined,
|
||||
onClick: undefined,
|
||||
...override,
|
||||
}
|
||||
|
||||
|
@ -46,27 +48,6 @@ describe('Card Select Card', () => {
|
|||
expect(field.prop('type')).toBe('checkbox')
|
||||
})
|
||||
|
||||
describe('toggleChecked method', () => {
|
||||
it('sets checked to true if false', () => {
|
||||
expect(wrapper.find('input').prop('checked')).toBe(false)
|
||||
wrapper
|
||||
.find('div')
|
||||
.filterWhere(div => div.prop('data-toggle'))
|
||||
.simulate('click', {preventDefault() {}})
|
||||
expect(wrapper.find('input').prop('checked')).toBe(true)
|
||||
})
|
||||
|
||||
it('sets checked to false if true', () => {
|
||||
wrapper = wrapperSetup({checked: true})
|
||||
expect(wrapper.find('input').prop('checked')).toBe(true)
|
||||
wrapper
|
||||
.find('div')
|
||||
.filterWhere(div => div.prop('data-toggle'))
|
||||
.simulate('click', {preventDefault() {}})
|
||||
expect(wrapper.find('input').prop('checked')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
it('matches snapshot with minimal props', () => {
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
|
||||
import CardSelectList from 'src/reusable_ui/components/card_select/CardSelectList'
|
||||
import CardSelectCard from 'src/reusable_ui/components/card_select/CardSelectCard'
|
||||
|
||||
describe('Card Select Card', () => {
|
||||
let wrapper
|
||||
|
||||
const wrapperSetup = (override = {}) => {
|
||||
const props = {
|
||||
children: undefined,
|
||||
legend: 'legend',
|
||||
...override,
|
||||
}
|
||||
|
||||
return shallow(<CardSelectList {...props} />)
|
||||
}
|
||||
|
||||
const childSetup = (override = {}) => {
|
||||
const props = {
|
||||
id: 'card_id',
|
||||
label: 'Card Label',
|
||||
image: undefined,
|
||||
checked: undefined,
|
||||
disabled: undefined,
|
||||
...override,
|
||||
}
|
||||
|
||||
return shallow(<CardSelectCard {...props} />)
|
||||
}
|
||||
|
||||
const cardChildren = [childSetup(), childSetup()]
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = wrapperSetup({children: cardChildren})
|
||||
})
|
||||
|
||||
it('mounts without exploding', () => {
|
||||
expect(wrapper).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('renders one fieldset', () => {
|
||||
expect(wrapper.find('fieldset')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('renders one legend', () => {
|
||||
expect(wrapper.find('legend')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('matches snapshot with two children', () => {
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
})
|
|
@ -2,81 +2,71 @@
|
|||
|
||||
exports[`Card Select Card matches snapshot with minimal props 1`] = `
|
||||
<div
|
||||
className="card-select--card-holder"
|
||||
className="card-select--card card-select--active"
|
||||
data-toggle="card_toggle"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="card-select--card card-select--active"
|
||||
data-toggle="card_toggle"
|
||||
onClick={[Function]}
|
||||
<label
|
||||
className="card-select--container"
|
||||
>
|
||||
<label
|
||||
className="card-select--container"
|
||||
<input
|
||||
checked={false}
|
||||
disabled={false}
|
||||
id="card_select_card_id"
|
||||
type="checkbox"
|
||||
value="card_id"
|
||||
/>
|
||||
<span
|
||||
className="card-select--checkmark icon checkmark"
|
||||
/>
|
||||
<div
|
||||
className="card-select--image"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
disabled={false}
|
||||
id="card_select_card_id"
|
||||
name="card_select_card_id"
|
||||
type="checkbox"
|
||||
value="card_id"
|
||||
/>
|
||||
<span
|
||||
className="card-select--checkmark icon checkmark"
|
||||
className="card-select--placeholder icon dash-j"
|
||||
/>
|
||||
<div
|
||||
className="card-select--image"
|
||||
>
|
||||
<span
|
||||
className="card-select--placeholder icon dash-j"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="card-select--label"
|
||||
>
|
||||
Card Label
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
className="card-select--label"
|
||||
>
|
||||
Card Label
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Card Select Card with image matches snapshot when provided image source 1`] = `
|
||||
<div
|
||||
className="card-select--card-holder"
|
||||
className="card-select--card card-select--active"
|
||||
data-toggle="card_toggle"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="card-select--card card-select--active"
|
||||
data-toggle="card_toggle"
|
||||
onClick={[Function]}
|
||||
<label
|
||||
className="card-select--container"
|
||||
>
|
||||
<label
|
||||
className="card-select--container"
|
||||
<input
|
||||
checked={false}
|
||||
disabled={false}
|
||||
id="card_select_card_id"
|
||||
type="checkbox"
|
||||
value="card_id"
|
||||
/>
|
||||
<span
|
||||
className="card-select--checkmark icon checkmark"
|
||||
/>
|
||||
<div
|
||||
className="card-select--image"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
disabled={false}
|
||||
id="card_select_card_id"
|
||||
name="card_select_card_id"
|
||||
type="checkbox"
|
||||
value="card_id"
|
||||
<img
|
||||
alt="Card Label icon"
|
||||
src="URL"
|
||||
/>
|
||||
<span
|
||||
className="card-select--checkmark icon checkmark"
|
||||
/>
|
||||
<div
|
||||
className="card-select--image"
|
||||
>
|
||||
<img
|
||||
alt="Card Label icon"
|
||||
src="URL"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="card-select--label"
|
||||
>
|
||||
Card Label
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
className="card-select--label"
|
||||
>
|
||||
Card Label
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Card Select Card matches snapshot with two children 1`] = `
|
||||
<fieldset
|
||||
className="card-select--wrapper"
|
||||
>
|
||||
<legend>
|
||||
legend
|
||||
</legend>
|
||||
<div
|
||||
className="card-select--cards"
|
||||
>
|
||||
<div
|
||||
className="card-select--card-holder"
|
||||
>
|
||||
<div
|
||||
className="card-select--card card-select--active"
|
||||
data-toggle="card_toggle"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<label
|
||||
className="card-select--container"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
disabled={false}
|
||||
id="card_select_card_id"
|
||||
name="card_select_card_id"
|
||||
type="checkbox"
|
||||
value="card_id"
|
||||
/>
|
||||
<span
|
||||
className="card-select--checkmark icon checkmark"
|
||||
/>
|
||||
<div
|
||||
className="card-select--image"
|
||||
>
|
||||
<span
|
||||
className="card-select--placeholder icon dash-j"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="card-select--label"
|
||||
>
|
||||
Card Label
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="card-select--card-holder"
|
||||
>
|
||||
<div
|
||||
className="card-select--card card-select--active"
|
||||
data-toggle="card_toggle"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<label
|
||||
className="card-select--container"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
disabled={false}
|
||||
id="card_select_card_id"
|
||||
name="card_select_card_id"
|
||||
type="checkbox"
|
||||
value="card_id"
|
||||
/>
|
||||
<span
|
||||
className="card-select--checkmark icon checkmark"
|
||||
/>
|
||||
<div
|
||||
className="card-select--image"
|
||||
>
|
||||
<span
|
||||
className="card-select--placeholder icon dash-j"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="card-select--label"
|
||||
>
|
||||
Card Label
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
`;
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Grid Sizer
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
$card-select--gutter: 4px;
|
||||
|
||||
.grid-sizer {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.grid-sizer--cell {
|
||||
float: left;
|
||||
position: relative;
|
||||
width: calc(100% - #{$card-select--gutter});
|
||||
height: calc(100% - #{$card-select--gutter});
|
||||
margin: $card-select--gutter / 2;
|
||||
}
|
||||
|
||||
.grid-sizer--col-2 {
|
||||
width: calc(50% - #{$card-select--gutter});
|
||||
padding-bottom: 50%;
|
||||
}
|
||||
|
||||
.grid-sizer--col-3 {
|
||||
width: calc(33.3333% - #{$card-select--gutter});
|
||||
padding-bottom: 33.3333%;
|
||||
}
|
||||
|
||||
.grid-sizer--col-4 {
|
||||
width: calc(25% - #{$card-select--gutter});
|
||||
padding-bottom: 25%;
|
||||
}
|
||||
|
||||
.grid-sizer--col-5 {
|
||||
width: calc(20% - #{$card-select--gutter});
|
||||
padding-bottom: 20%;
|
||||
}
|
||||
|
||||
.grid-sizer--col-6 {
|
||||
width: calc(16.6667% - #{$card-select--gutter});
|
||||
padding-bottom: 16.6667%;
|
||||
}
|
||||
|
||||
.grid-sizer--content {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
children?: JSX.Element[]
|
||||
cellWidth?: number
|
||||
width?: number
|
||||
}
|
||||
|
||||
interface State {
|
||||
columns: number
|
||||
}
|
||||
@ErrorHandling
|
||||
class CardSelectList extends PureComponent<Props, State> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
cellWidth: 160,
|
||||
width: null,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
columns: null,
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
const {width} = this.props
|
||||
const widthValue = width || this.getWidth()
|
||||
this.setColumns(widthValue)
|
||||
|
||||
if (!width) {
|
||||
window.addEventListener(
|
||||
'resize',
|
||||
_.debounce(() => this.setColumns(this.getWidth()), 250),
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
const {width} = this.props
|
||||
if (width) {
|
||||
this.setColumns(width)
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener(
|
||||
'resize',
|
||||
_.debounce(() => this.setColumns(this.getWidth()), 250),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div id="grid_sizer" className="grid-sizer">
|
||||
{this.sizeChildren}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get sizeChildren() {
|
||||
const {columns} = this.state
|
||||
const {children} = this.props
|
||||
|
||||
if (columns) {
|
||||
const wrappedChildren = children.map((child, i) => (
|
||||
<div
|
||||
key={`grid_cell_${i}`}
|
||||
className={`grid-sizer--cell grid-sizer--col-${columns}`}
|
||||
>
|
||||
<div className="grid-sizer--content">{child}</div>
|
||||
</div>
|
||||
))
|
||||
|
||||
return wrappedChildren
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
private getWidth = () => {
|
||||
const ele = document.getElementById('grid_sizer')
|
||||
const computedWidth = window
|
||||
.getComputedStyle(ele, null)
|
||||
.getPropertyValue('width')
|
||||
|
||||
const widthValue = Number(
|
||||
computedWidth.substring(0, computedWidth.length - 2)
|
||||
)
|
||||
|
||||
return widthValue
|
||||
}
|
||||
|
||||
private setColumns = (width: number) => {
|
||||
const {cellWidth} = this.props
|
||||
const columns = Math.round(width / cellWidth)
|
||||
|
||||
this.setState({
|
||||
columns,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default CardSelectList
|
|
@ -7,6 +7,7 @@
|
|||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: $ix-marg-b 0 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wizard-step--child {
|
||||
|
|
|
@ -9,10 +9,11 @@ import WizardOverlay from 'src/reusable_ui/components/wizard/WizardOverlay'
|
|||
import WizardStep from 'src/reusable_ui/components/wizard/WizardStep'
|
||||
import SourceStep from 'src/sources/components/SourceStep'
|
||||
import KapacitorStep from 'src/sources/components/KapacitorStep'
|
||||
import DashboardStep from 'src/sources/components/DashboardStep'
|
||||
import CompletionStep from 'src/sources/components/CompletionStep'
|
||||
|
||||
// Types
|
||||
import {Kapacitor, Source} from 'src/types'
|
||||
import {Kapacitor, Source, Protoboard} from 'src/types'
|
||||
import {ToggleWizard} from 'src/types/wizard'
|
||||
|
||||
interface Props {
|
||||
|
@ -28,6 +29,8 @@ interface State {
|
|||
sourceError: boolean
|
||||
kapacitor: Kapacitor
|
||||
kapacitorError: boolean
|
||||
dashboardError: boolean
|
||||
dashboards: Protoboard[]
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -43,6 +46,7 @@ class ConnectionWizard extends PureComponent<Props & WithRouterProps, State> {
|
|||
public sourceStepRef: any
|
||||
public kapacitorStepRef: any
|
||||
public completionStepRef: any
|
||||
public dashboardStepRef: any
|
||||
|
||||
constructor(props: Props & WithRouterProps) {
|
||||
super(props)
|
||||
|
@ -51,12 +55,21 @@ class ConnectionWizard extends PureComponent<Props & WithRouterProps, State> {
|
|||
kapacitor: null,
|
||||
sourceError: false,
|
||||
kapacitorError: false,
|
||||
dashboardError: false,
|
||||
dashboards: null,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {isVisible, toggleVisibility, jumpStep, showNewKapacitor} = this.props
|
||||
const {source, sourceError, kapacitor, kapacitorError} = this.state
|
||||
const {
|
||||
source,
|
||||
sourceError,
|
||||
kapacitor,
|
||||
kapacitorError,
|
||||
dashboardError,
|
||||
} = this.state
|
||||
|
||||
return (
|
||||
<WizardOverlay
|
||||
visible={isVisible}
|
||||
|
@ -102,6 +115,13 @@ class ConnectionWizard extends PureComponent<Props & WithRouterProps, State> {
|
|||
showNewKapacitor={showNewKapacitor}
|
||||
/>
|
||||
</WizardStep>
|
||||
<WizardStep
|
||||
title="Select Dashboards"
|
||||
isComplete={this.isDashboardComplete}
|
||||
isErrored={dashboardError}
|
||||
>
|
||||
{this.dashboardStep}
|
||||
</WizardStep>
|
||||
<WizardStep
|
||||
title="Setup Complete"
|
||||
tipText=""
|
||||
|
@ -120,6 +140,16 @@ class ConnectionWizard extends PureComponent<Props & WithRouterProps, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get dashboardStep() {
|
||||
const {dashboards} = this.state
|
||||
|
||||
if (dashboards) {
|
||||
return <DashboardStep dashboards={dashboards} />
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private handleSourceNext = async () => {
|
||||
const response = await this.sourceStepRef.next()
|
||||
this.setState({source: response.payload})
|
||||
|
@ -147,6 +177,10 @@ class ConnectionWizard extends PureComponent<Props & WithRouterProps, State> {
|
|||
this.setState({kapacitorError: b})
|
||||
}
|
||||
|
||||
private isDashboardComplete = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
private isCompletionComplete = () => {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
.dashboard-step {
|
||||
position: relative;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// Libraries
|
||||
import React, {Component} from 'react'
|
||||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import GridSizer from 'src/reusable_ui/components/grid_sizer/GridSizer'
|
||||
import CardSelectCard from 'src/reusable_ui/components/card_select/CardSelectCard'
|
||||
|
||||
// Types
|
||||
import {Protoboard} from 'src/types'
|
||||
|
||||
interface State {
|
||||
selected: object
|
||||
}
|
||||
|
||||
interface Props {
|
||||
dashboards?: Protoboard[]
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class DashboardStep extends Component<Props, State> {
|
||||
public constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
selected: {},
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div className="dashboard-step">
|
||||
<GridSizer>{this.dashboardCards}</GridSizer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get dashboardCards() {
|
||||
const {selected} = this.state
|
||||
const {dashboards} = this.props
|
||||
|
||||
const cards =
|
||||
dashboards &&
|
||||
dashboards.map((dashboard, i) => {
|
||||
const {meta} = dashboard
|
||||
return (
|
||||
<CardSelectCard
|
||||
key={`${dashboard.id}_${i}`}
|
||||
id={meta.name}
|
||||
name={meta.name}
|
||||
label={meta.name}
|
||||
checked={selected[meta.name]}
|
||||
onClick={this.toggleChecked(meta.name)}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
if (cards.length) {
|
||||
return cards
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private toggleChecked = (name: string) => () => {
|
||||
const {selected} = this.state
|
||||
|
||||
const newSelected = selected
|
||||
|
||||
if (selected[name]) {
|
||||
newSelected[name] = false
|
||||
} else {
|
||||
newSelected[name] = true
|
||||
}
|
||||
|
||||
this.setState({
|
||||
selected: newSelected,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default DashboardStep
|
|
@ -73,6 +73,7 @@
|
|||
@import 'components/histogram-chart';
|
||||
@import 'src/sources/components/ConnectionLink';
|
||||
@import 'src/sources/components/KapacitorStep';
|
||||
@import 'src/sources/components/DashboardStep';
|
||||
|
||||
|
||||
// Reusable UI Components
|
||||
|
@ -82,6 +83,7 @@
|
|||
@import '../reusable_ui/components/overlays/Overlay.scss';
|
||||
@import '../dashboards/components/import_dashboard_mappings/ImportDashboardMappings.scss';
|
||||
@import '../reusable_ui/components/card_select/CardSelectCard.scss';
|
||||
@import '../reusable_ui/components/grid_sizer/GridSizer.scss';
|
||||
@import '../reusable_ui/components/wizard/WizardController.scss';
|
||||
@import '../reusable_ui/components/wizard/WizardButtonBar.scss';
|
||||
@import '../reusable_ui/components/wizard/WizardFullScreen.scss';
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
export interface CardSelectCardProps {
|
||||
id: string
|
||||
label: string
|
||||
image?: string
|
||||
checked?: boolean
|
||||
disabled?: boolean
|
||||
}
|
|
@ -199,3 +199,23 @@ export type NewDefaultCell = Pick<
|
|||
Cell,
|
||||
Exclude<keyof Cell, 'i' | 'axes' | 'colors' | 'links' | 'legend'>
|
||||
>
|
||||
|
||||
export interface ProtoboardMetadata {
|
||||
name: string
|
||||
icon: string
|
||||
version: string
|
||||
dashboardVersion: string
|
||||
description: string
|
||||
author: string
|
||||
license: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface ProtoboardData {
|
||||
cells: object
|
||||
}
|
||||
export interface Protoboard {
|
||||
id: string
|
||||
meta: ProtoboardMetadata
|
||||
data: ProtoboardData
|
||||
}
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
import {LayoutCell, LayoutQuery} from './layouts'
|
||||
import {Service, NewService, ServiceLinks} from './services'
|
||||
import {Links, Organization, Role, Permission, User, Me} from './auth'
|
||||
import {Cell, CellQuery, Legend, Axes, Dashboard, CellType} from './dashboards'
|
||||
import {
|
||||
Cell,
|
||||
CellQuery,
|
||||
Legend,
|
||||
Axes,
|
||||
Dashboard,
|
||||
CellType,
|
||||
Protoboard,
|
||||
} from './dashboards'
|
||||
import {
|
||||
Template,
|
||||
TemplateQuery,
|
||||
|
@ -66,6 +74,7 @@ export {
|
|||
Cell,
|
||||
CellQuery,
|
||||
CellType,
|
||||
Protoboard,
|
||||
Legend,
|
||||
Status,
|
||||
Query,
|
||||
|
|
Loading…
Reference in New Issue