Skip to content

Commit

Permalink
feat(flows): redesign add cell UX (#18973)
Browse files Browse the repository at this point in the history
* refactor: consolidate header component & remove add buttons

* feat: render add cell buttons in empty state

* refactor: make inline insert button more visible on hover

* refactor: remove feature flag around Data Source cell type

* feat: group cell types into "families"

* refactor: rename "Data Source" to "Bucket"

* refactor: render cell types in families inside add cell menu

* fix: make it a little more flexible (#18976)

Co-authored-by: drdelambre <drdelambre>

* fix: linting issue

Co-authored-by: Alex Boatwright <drdelambre@gmail.com>
Co-authored-by: drdelambre <drdelambre>
  • Loading branch information
alexpaxton and drdelambre authored Jul 17, 2020
1 parent c476da2 commit 6c714b1
Show file tree
Hide file tree
Showing 22 changed files with 217 additions and 97 deletions.
34 changes: 34 additions & 0 deletions ui/src/notebooks/components/AddButtons.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@import '@influxdata/clockface/dist/variables.scss';

.add-cell-menu {
display: flex;
align-items: stretch;
}

.add-cell-menu--column {
display: flex;
flex-direction: column;
align-items: stretch;
flex: 1 0 142px;
width: 142px;
background-color: $g1-raven;
border-radius: $cf-radius;
padding: 0 $cf-marg-c;
margin-right: $cf-marg-a;

&:last-child {
margin-right: 0;
}
}

.add-cell-menu--column .cf-button {
margin-bottom: $cf-marg-b;
}

.add-cell-menu--column-title {
white-space: nowrap;
margin: $cf-marg-b 0;
text-align: center;
padding: 0 $cf-marg-b;
user-select: none;
}
81 changes: 69 additions & 12 deletions ui/src/notebooks/components/AddButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,92 @@ import React, {FC, useContext} from 'react'

// Components
import {Button, ComponentColor} from '@influxdata/clockface'
import CellFamily from 'src/notebooks/components/CellFamily'

// Constants
import {NotebookContext} from 'src/notebooks/context/notebook.current'
import {ResultsContext} from 'src/notebooks/context/results'
import {PIPE_DEFINITIONS} from 'src/notebooks'

// Utils
import {event} from 'src/cloud/utils/reporting'
import {isFlagEnabled} from 'src/shared/utils/featureFlag'

import {TypeRegistration} from 'src/notebooks'

// Styles
import 'src/notebooks/components/AddButtons.scss'

interface Props {
index?: number
onInsert?: () => void
eventName: string
}

const SUPPORTED_FAMILIES = [
{
name: 'Input',
family: 'inputs',
},
{
name: 'Transform',
family: 'transform',
},
{
name: 'Pass Throughs',
family: 'passThrough',
},
{
name: 'Test',
family: 'test',
},
{
name: 'Output',
family: 'output',
},
{
name: 'Side Effects',
family: 'sideEffects',
},
]

const AddButtons: FC<Props> = ({index, onInsert, eventName}) => {
const {add} = useContext(NotebookContext)
const results = useContext(ResultsContext)

const pipes = Object.entries(PIPE_DEFINITIONS)
.filter(
([_, def]) =>
!def.disabled && (!def.featureFlag || isFlagEnabled(def.featureFlag))
)
.sort((a, b) => {
const aPriority = a[1].priority || 0
const bPriority = b[1].priority || 0
const pipeFamilies = Object.entries(
Object.values(PIPE_DEFINITIONS)
.filter(
def =>
!def.disabled && (!def.featureFlag || isFlagEnabled(def.featureFlag))
)
.reduce((acc, def) => {
if (!acc.hasOwnProperty(def.family)) {
acc[def.family] = []
}

acc[def.family].push(def)

return acc
}, {})
).reduce((acc, [key, val]) => {
acc[key] = (val as TypeRegistration[]).sort((a, b) => {
const aPriority = a.priority || 0
const bPriority = b.priority || 0

if (aPriority === bPriority) {
return a[1].button.localeCompare(b[1].button)
return a.button.localeCompare(b.button)
}

return bPriority - aPriority
})
.map(([type, def]) => {
return acc
}, {})

const cellFamilies = SUPPORTED_FAMILIES.filter(fam =>
pipeFamilies.hasOwnProperty(fam.family)
).map(fam => {
const pipes = pipeFamilies[fam.family].map(def => {
return (
<Button
key={def.type}
Expand All @@ -57,7 +108,7 @@ const AddButtons: FC<Props> = ({index, onInsert, eventName}) => {
const id = add(
{
...data,
type,
type: def.type,
},
index
)
Expand All @@ -68,8 +119,14 @@ const AddButtons: FC<Props> = ({index, onInsert, eventName}) => {
/>
)
})
return (
<CellFamily key={fam.name} title={fam.name}>
{pipes}
</CellFamily>
)
})

return <>{pipes}</>
return <div className="add-cell-menu">{cellFamilies}</div>
}

export default AddButtons
22 changes: 22 additions & 0 deletions ui/src/notebooks/components/CellFamily.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Libraries
import React, {FC, ReactNode, Children} from 'react'

interface Props {
title: string
children: ReactNode
}

const CellFamily: FC<Props> = ({title, children}) => {
if (Children.count(children) === 0) {
return null
}

return (
<div className="add-cell-menu--column">
<h6 className="add-cell-menu--column-title">{title}</h6>
{children}
</div>
)
}

export default CellFamily
4 changes: 4 additions & 0 deletions ui/src/notebooks/components/EmptyPipeList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@
background-position: center center;
background-repeat: no-repeat;
}

.notebook-empty--buttons {
margin-top: $cf-marg-c;
}
8 changes: 7 additions & 1 deletion ui/src/notebooks/components/EmptyPipeList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Libraries
import React, {FC} from 'react'

// Components
import AddButtons from 'src/notebooks/components/AddButtons'

// Styles
import 'src/notebooks/components/EmptyPipeList.scss'

Expand All @@ -14,8 +17,11 @@ const EmptyPipeList: FC = () => {
alert on your data
</p>
<p>
Get started by <strong>Adding a Cell</strong> from the top left menu
Get started by <strong>Adding a Cell</strong> below
</p>
<div className="notebook-empty--buttons">
<AddButtons eventName="Add from empty" />
</div>
</div>
)
}
Expand Down
4 changes: 2 additions & 2 deletions ui/src/notebooks/components/Notebook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {ResultsProvider} from 'src/notebooks/context/results'
import {RefProvider} from 'src/notebooks/context/refs'
import CurrentNotebook from 'src/notebooks/context/notebook.current'
import {ScrollProvider} from 'src/notebooks/context/scroll'
import Header from 'src/notebooks/components/header'
import NotebookHeader from 'src/notebooks/components/header'
import PipeList from 'src/notebooks/components/PipeList'
import MiniMap from 'src/notebooks/components/minimap/MiniMap'

Expand All @@ -23,7 +23,7 @@ const NotebookPage: FC = () => {
<RefProvider>
<ScrollProvider>
<Page titleTag="Flows">
<Header />
<NotebookHeader />
<Page.Contents
fullWidth={true}
scrollable={false}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/notebooks/components/header/AutoRefreshDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {FC, useMemo, useCallback} from 'react'
import {default as StatelessAutoRefreshDropdown} from 'src/shared/components/dropdown_auto_refresh/AutoRefreshDropdown'
import {TimeContextProps} from 'src/notebooks/components/header/Buttons'
import {TimeContextProps} from 'src/notebooks/components/header'
import {TimeBlock} from 'src/notebooks/context/time'
import {AutoRefreshStatus} from 'src/types'

Expand Down
59 changes: 0 additions & 59 deletions ui/src/notebooks/components/header/Buttons.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion ui/src/notebooks/components/header/TimeRangeDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {FC, useMemo, useCallback} from 'react'
import {default as StatelessTimeRangeDropdown} from 'src/shared/components/TimeRangeDropdown'
import {TimeContextProps} from 'src/notebooks/components/header/Buttons'
import {TimeContextProps} from 'src/notebooks/components/header'
import {TimeBlock} from 'src/notebooks/context/time'

// Utils
Expand Down
63 changes: 49 additions & 14 deletions ui/src/notebooks/components/header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,68 @@
import React, {FC, useContext} from 'react'
// Libraries
import React, {FC, useContext, useCallback} from 'react'

// Contexts
import {NotebookContext} from 'src/notebooks/context/notebook'
import {TimeProvider, TimeContext, TimeBlock} from 'src/notebooks/context/time'
import AppSettingProvider from 'src/notebooks/context/app'

// Components
import {Page} from '@influxdata/clockface'
import AddButtons from 'src/notebooks/components/AddButtons'
import Buttons from 'src/notebooks/components/header/Buttons'
import {NotebookContext} from 'src/notebooks/context/notebook.current'
import TimeZoneDropdown from 'src/notebooks/components/header/TimeZoneDropdown'
import TimeRangeDropdown from 'src/notebooks/components/header/TimeRangeDropdown'
import AutoRefreshDropdown from 'src/notebooks/components/header/AutoRefreshDropdown'
import Submit from 'src/notebooks/components/header/Submit'
import PresentationMode from 'src/notebooks/components/header/PresentationMode'

const FULL_WIDTH = true

const Header: FC = () => {
const {notebook} = useContext(NotebookContext)
export interface TimeContextProps {
context: TimeBlock
update: (data: TimeBlock) => void
}

const NotebookHeader: FC = () => {
const {id} = useContext(NotebookContext)
const {timeContext, addTimeContext, updateTimeContext} = useContext(
TimeContext
)

const update = useCallback(
(data: TimeBlock) => {
updateTimeContext(id, data)
},
[id, updateTimeContext]
)

if (!timeContext.hasOwnProperty(id)) {
addTimeContext(id)
return null
}

return (
<>
<Page.Header fullWidth={FULL_WIDTH}>
<Page.Title title="Flows" />
</Page.Header>
<Page.ControlBar fullWidth={FULL_WIDTH}>
{!notebook.readOnly && (
<Page.ControlBarLeft>
<h3 className="notebook--add-cell-label">Add Cell:</h3>
<AddButtons eventName="Notebook Add Button Clicked" />
</Page.ControlBarLeft>
)}
<Page.ControlBarLeft>
<Submit />
</Page.ControlBarLeft>
<Page.ControlBarRight>
<Buttons />
<PresentationMode />
<TimeZoneDropdown />
<TimeRangeDropdown context={timeContext[id]} update={update} />
<AutoRefreshDropdown context={timeContext[id]} update={update} />
</Page.ControlBarRight>
</Page.ControlBar>
</>
)
}

export default Header
export default () => (
<TimeProvider>
<AppSettingProvider>
<NotebookHeader />
</AppSettingProvider>
</TimeProvider>
)
Loading

0 comments on commit 6c714b1

Please sign in to comment.