feat(notebooks): display raw data within query pipes (#18341)

* refactor: add left indentation on all pipes to make titles easier to scan

* refactor: store results in raw and parsed formats

This intended is a bandaid fix until raw data table comes from Giraffe and accepts data in the standard way

* refactor: remove unused scss variable

* feat: create raw data components and display within query pipes

* fix: remove console log

* refactor: begone lodash
pull/18357/head
alexpaxton 2020-06-02 16:18:47 -07:00 committed by GitHub
parent fd289883fe
commit b4f4a11cff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 270 additions and 19 deletions

View File

@ -12,7 +12,7 @@ const Pipe: FC<PipeProp> = props => {
return useMemo(
() => createElement(PIPE_DEFINITIONS[data.type].component, props),
[props.data]
[props.data, props.results]
)
}

View File

@ -11,7 +11,7 @@ import EmptyPipeList from 'src/notebooks/components/EmptyPipeList'
import {DapperScrollbars} from '@influxdata/clockface'
const PipeList: FC = () => {
const {id, pipes, updatePipe} = useContext(NotebookContext)
const {id, pipes, updatePipe, results} = useContext(NotebookContext)
const {scrollPosition} = useContext(ScrollContext)
const update = useCallback(updatePipe, [id])
@ -26,6 +26,7 @@ const PipeList: FC = () => {
index={index}
data={pipes[index]}
onUpdate={update}
results={results[index]}
/>
)
})

View File

@ -1,7 +1,7 @@
import React, {FC, useState, useCallback, RefObject} from 'react'
import {RemoteDataState} from 'src/types'
import {PipeData} from 'src/notebooks'
import {FromFluxResult} from '@influxdata/giraffe'
import {BothResults} from 'src/notebooks/context/query'
export interface PipeMeta {
title: string
@ -16,11 +16,11 @@ export interface NotebookContextType {
id: string
pipes: PipeData[]
meta: PipeMeta[] // data only used for the view layer for Notebooks
results: FromFluxResult[]
results: BothResults[]
addPipe: (pipe: PipeData) => void
updatePipe: (idx: number, pipe: PipeData) => void
updateMeta: (idx: number, pipe: PipeMeta) => void
updateResult: (idx: number, result: FromFluxResult) => void
updateResult: (idx: number, result: BothResults) => void
movePipe: (currentIdx: number, newIdx: number) => void
removePipe: (idx: number) => void
}
@ -115,11 +115,11 @@ export const NotebookProvider: FC = ({children}) => {
)
const updateResult = useCallback(
(idx: number, results: FromFluxResult) => {
(idx: number, results: BothResults) => {
_setResults(pipes => {
pipes[idx] = {
...results,
} as FromFluxResult
} as BothResults
return pipes.slice()
})
},

View File

@ -11,12 +11,17 @@ import {NotebookContext} from 'src/notebooks/context/notebook'
import {TimeContext} from 'src/notebooks/context/time'
import {fromFlux as parse, FromFluxResult} from '@influxdata/giraffe'
export interface BothResults {
parsed: FromFluxResult
raw: string
}
export interface QueryContextType {
query: (text: string) => Promise<FromFluxResult>
query: (text: string) => Promise<BothResults>
}
export const DEFAULT_CONTEXT: QueryContextType = {
query: () => Promise.resolve({} as FromFluxResult),
query: () => Promise.resolve({} as BothResults),
}
export const QueryContext = React.createContext<QueryContextType>(
@ -48,7 +53,10 @@ export const QueryProvider: FC<Props> = ({children, variables, org}) => {
return raw
})
.then(raw => {
return parse(raw.csv)
return {
raw: raw.csv,
parsed: parse(raw.csv),
}
})
}

View File

@ -1,5 +1,5 @@
import {FunctionComponent, ComponentClass, ReactNode} from 'react'
import {FromFluxResult} from '@influxdata/giraffe'
import {BothResults} from 'src/notebooks/context/query'
export interface PipeContextProps {
children?: ReactNode
@ -11,7 +11,7 @@ export type PipeData = any
export interface PipeProp {
data: PipeData
onUpdate: (data: PipeData) => void
results?: FromFluxResult
results?: BothResults
Context:
| FunctionComponent<PipeContextProps>

View File

@ -0,0 +1,63 @@
// Libraries
import React, {FC} from 'react'
import {BothResults} from 'src/notebooks/context/query'
import {AutoSizer} from 'react-virtualized'
import classnames from 'classnames'
// Components
import RawFluxDataTable from 'src/timeMachine/components/RawFluxDataTable'
import ResultsHeader from 'src/notebooks/pipes/Query/ResultsHeader'
// Types
import {RawDataSize} from 'src/notebooks/pipes/Query'
interface Props {
results: BothResults
size: RawDataSize
onUpdateSize: (size: RawDataSize) => void
}
const Results: FC<Props> = ({results, size, onUpdateSize}) => {
const resultsExist = !!results.raw
const className = classnames('notebook-raw-data', {
[`notebook-raw-data__${size}`]: resultsExist && size,
})
let resultsBody = (
<div className="notebook-raw-data--empty">
Run the Notebook to see results
</div>
)
if (resultsExist) {
resultsBody = (
<div className="notebook-raw-data--body">
<AutoSizer>
{({width, height}) =>
width &&
height && (
<RawFluxDataTable
files={[results.raw]}
width={width}
height={height}
/>
)
}
</AutoSizer>
</div>
)
}
return (
<div className={className}>
<ResultsHeader
resultsExist={resultsExist}
size={size}
onUpdateSize={onUpdateSize}
/>
{resultsBody}
</div>
)
}
export default Results

View File

@ -0,0 +1,55 @@
// Libraries
import React, {FC} from 'react'
import classnames from 'classnames'
// Components
import {Icon, IconFont} from '@influxdata/clockface'
// Types
import {RawDataSize} from 'src/notebooks/pipes/Query'
interface Props {
resultsExist: boolean
size: RawDataSize
onUpdateSize: (size: RawDataSize) => void
}
const ResultsHeader: FC<Props> = ({resultsExist, size, onUpdateSize}) => {
if (!resultsExist) {
return (
<div className="notebook-raw-data--header">
<Icon glyph={IconFont.DashF} />
</div>
)
}
const handleClick = (newSize: RawDataSize) => (): void => {
onUpdateSize(newSize)
}
const generateClassName = (buttonSize: RawDataSize): string => {
return classnames('notebook-raw-data--size-toggle', {
[`notebook-raw-data--size-toggle__${buttonSize}`]: buttonSize,
'notebook-raw-data--size-toggle__active': buttonSize === size,
})
}
return (
<div className="notebook-raw-data--header">
<div
className={generateClassName('small')}
onClick={handleClick('small')}
/>
<div
className={generateClassName('medium')}
onClick={handleClick('medium')}
/>
<div
className={generateClassName('large')}
onClick={handleClick('large')}
/>
</div>
)
}
export default ResultsHeader

View File

@ -2,11 +2,14 @@ import {register} from 'src/notebooks'
import View from './view'
import './style.scss'
export type RawDataSize = 'small' | 'medium' | 'large'
register({
type: 'query',
component: View,
button: 'Custom Script',
initial: {
rawDataSize: 'small',
activeQuery: 0,
queries: [
{

View File

@ -1,8 +1,114 @@
@import '@influxdata/clockface/dist/variables.scss';
$notebook-results-header: 47px;
$notebook-results-small: 200px;
$notebook-results-medium: 400px;
$notebook-results-large: 600px;
.notebook-panel--body .flux-editor--monaco {
position: relative;
.react-monaco-editor-container {
min-height: 100px;
min-height: 100px;
}
}
.notebook-raw-data {
margin-top: $cf-marg-a;
display: flex;
flex-direction: row;
align-items: stretch;
width: 100%;
border: $cf-border solid $g2-kevlar;
background-color: $g2-kevlar;
border-radius: $cf-radius 0 0 $cf-radius;
}
.notebook-raw-data__small {
height: $notebook-results-small;
}
.notebook-raw-data__medium {
height: $notebook-results-medium;
}
.notebook-raw-data__large {
height: $notebook-results-large;
}
.notebook-raw-data--header {
color: $g8-storm;
width: $notebook-results-header;
flex: 0 0 $notebook-results-header;
display: flex;
flex-direction: column;
align-items: center;
padding: $cf-marg-b 0;
}
.notebook-raw-data--body,
.notebook-raw-data--empty {
position: relative;
flex: 1 0 0;
}
.notebook-raw-data--empty {
color: $g8-storm;
user-select: none;
padding: $cf-marg-b 0;
font-weight: $cf-font-weight--medium;
}
.notebook-raw-data__success {
height: 200px;
}
.notebook-raw-data--size-toggle {
border-radius: 50%;
position: relative;
width: 24px;
height: 24px;
margin-bottom: $cf-marg-a;
border: $cf-border solid $g3-castle;
background-color: $g1-raven;
transition: background-color 0.25s ease;
&:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
transition: width 0.25s ease, height 0.25s ease, background-color 0.25s ease;
transform: translate(-50%, -50%);
background-color: $g5-pepper;
}
&:hover {
cursor: pointer;
&:after {
background-color: $g7-graphite;
}
}
}
.notebook-raw-data--size-toggle__active:after,
.notebook-raw-data--size-toggle__active:hover:after {
background-color: $c-pool;
}
.notebook-raw-data--size-toggle__small:after {
width: 8px;
height: 8px;
}
.notebook-raw-data--size-toggle__medium:after {
width: 12px;
height: 12px;
}
.notebook-raw-data--size-toggle__large:after {
width: 16px;
height: 16px;
}

View File

@ -1,10 +1,21 @@
// Libraries
import React, {FC, useMemo} from 'react'
import {PipeProp} from 'src/notebooks'
import FluxMonacoEditor from 'src/shared/components/FluxMonacoEditor'
const Query: FC<PipeProp> = ({data, onUpdate, Context}) => {
// Types
import {PipeProp} from 'src/notebooks'
import {RawDataSize} from 'src/notebooks/pipes/Query'
// Components
import FluxMonacoEditor from 'src/shared/components/FluxMonacoEditor'
import Results from 'src/notebooks/pipes/Query/Results'
// Styles
import 'src/notebooks/pipes/Query/style.scss'
const Query: FC<PipeProp> = ({data, onUpdate, Context, results}) => {
const {queries, activeQuery} = data
const query = queries[activeQuery]
const size = data.rawDataSize || 'small'
function updateText(text) {
const _queries = queries.slice()
@ -16,6 +27,10 @@ const Query: FC<PipeProp> = ({data, onUpdate, Context}) => {
onUpdate({queries: _queries})
}
const onUpdateSize = (rawDataSize: RawDataSize): void => {
onUpdate({rawDataSize})
}
return useMemo(
() => (
<Context>
@ -25,9 +40,10 @@ const Query: FC<PipeProp> = ({data, onUpdate, Context}) => {
onSubmitScript={() => {}}
autogrow
/>
<Results results={results} size={size} onUpdateSize={onUpdateSize} />
</Context>
),
[query.text]
[query.text, results, data.rawDataSize]
)
}

View File

@ -1,7 +1,5 @@
@import '@influxdata/clockface/dist/variables.scss';
$notebook-panel--bg: mix($g1-raven, $g2-kevlar, 50%);
.notebook-panel--markdown {
font-size: 14px;
line-height: 16px;

View File

@ -133,6 +133,7 @@
.notebook-panel--body {
border-radius: 0 0 $cf-radius $cf-radius;
padding: $cf-marg-b;
padding-left: $cf-marg-d;
padding-top: 0;
position: relative;
}