Skip to content

Commit

Permalink
feat: add query type for notebooks (#18168)
Browse files Browse the repository at this point in the history
  • Loading branch information
drdelambre authored May 22, 2020
1 parent 78466ba commit 6e67fb4
Show file tree
Hide file tree
Showing 17 changed files with 342 additions and 219 deletions.
32 changes: 18 additions & 14 deletions ui/src/buckets/actions/thunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ import {LIMIT} from 'src/resources/constants'

type Action = BucketAction | NotifyAction

export const fetchAllBuckets = async (orgID: string) => {
const resp = await api.getBuckets({
query: {orgID, limit: LIMIT},
})

if (resp.status !== 200) {
throw new Error(resp.data.message)
}

const demoDataBuckets = await fetchDemoDataBuckets()

return normalize<Bucket, BucketEntities, string[]>(
[...resp.data.buckets, ...demoDataBuckets],
arrayOfBuckets
)
}

export const getBuckets = () => async (
dispatch: Dispatch<Action>,
getState: GetState
Expand All @@ -65,20 +82,7 @@ export const getBuckets = () => async (
}
const org = getOrg(state)

const resp = await api.getBuckets({
query: {orgID: org.id, limit: LIMIT},
})

if (resp.status !== 200) {
throw new Error(resp.data.message)
}

const demoDataBuckets = await fetchDemoDataBuckets()

const buckets = normalize<Bucket, BucketEntities, string[]>(
[...resp.data.buckets, ...demoDataBuckets],
arrayOfBuckets
)
const buckets = await fetchAllBuckets(org.id)

dispatch(setBuckets(RemoteDataState.Done, buckets))
} catch (error) {
Expand Down
33 changes: 18 additions & 15 deletions ui/src/external/monaco.flux.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {getAllVariables, asAssignment} from 'src/variables/selectors'
import {buildVarsOption} from 'src/variables/utils/buildVarsOption'
import {runQuery} from 'src/shared/apis/query'
import {parseResponse as parse} from 'src/shared/parsing/flux/response'
import {getOrg} from 'src/organizations/selectors'
import {fetchAllBuckets} from 'src/buckets/actions/thunks'

import {store} from 'src/index'

Expand Down Expand Up @@ -109,8 +111,6 @@ const queryTagValues = async (orgID, bucket, tag) => {
export class LSPServer {
private server: WASMServer
private messageID: number = 0
private buckets: string[] = []
private orgID: string = ''
private documentVersions: {[key: string]: number} = {}
public store: Store<AppState & LocalStorage>

Expand All @@ -125,7 +125,8 @@ export class LSPServer {

getTagKeys = async bucket => {
try {
const response = await queryTagKeys(this.orgID, bucket)
const org = getOrg(this.store.getState())
const response = await queryTagKeys(org.id, bucket)
return parseQueryResponse(response)
} catch (e) {
console.error(e)
Expand All @@ -135,36 +136,38 @@ export class LSPServer {

getTagValues = async (bucket, tag) => {
try {
const response = await queryTagValues(this.orgID, bucket, tag)
const org = getOrg(this.store.getState())
const response = await queryTagValues(org.id, bucket, tag)
return parseQueryResponse(response)
} catch (e) {
console.error(e)
return []
}
}

getBuckets = () => {
return Promise.resolve(this.buckets)
getBuckets = async () => {
try {
const org = getOrg(this.store.getState())
const buckets = await fetchAllBuckets(org.id)

return Object.values(buckets.entities.buckets).map(b => b.name)
} catch (e) {
console.error(e)
return []
}
}

getMeasurements = async (bucket: string) => {
try {
const response = await queryMeasurements(this.orgID, bucket)
const org = getOrg(this.store.getState())
const response = await queryMeasurements(org.id, bucket)
return parseQueryResponse(response)
} catch (e) {
console.error(e)
return []
}
}

updateBuckets(buckets: string[]) {
this.buckets = buckets
}

setOrg(orgID: string) {
this.orgID = orgID
}

initialize() {
return this.send(initialize(this.currentMessageID))
}
Expand Down
91 changes: 62 additions & 29 deletions ui/src/notebooks/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {FC, useContext} from 'react'
import React, {FC, useContext, useCallback, useMemo} from 'react'

import {Page} from '@influxdata/clockface'
import {NotebookContext} from 'src/notebooks/context/notebook'
Expand All @@ -14,39 +14,81 @@ import {SubmitQueryButton} from 'src/timeMachine/components/SubmitQueryButton'

const FULL_WIDTH = true

const Header: FC = () => {
const {id} = useContext(NotebookContext)
const {timeContext, addTimeContext, updateTimeContext} = useContext(
TimeContext
)
const ConnectedTimeZoneDropdown = React.memo(() => {
const {timeZone, onSetTimeZone} = useContext(AppSettingContext)

if (!timeContext.hasOwnProperty(id)) {
addTimeContext(id)
return null
return <TimeZoneDropdown timeZone={timeZone} onSetTimeZone={onSetTimeZone} />
})

const ConnectedTimeRangeDropdown = ({context, update}) => {
const {range} = context

const updateRange = range => {
update({
range,
})
}

const {refresh, range} = timeContext[id]
return useMemo(() => {
return <TimeRangeDropdown timeRange={range} onSetTimeRange={updateRange} />
}, [range])
}

const ConnectedAutoRefreshDropdown = ({context, update}) => {
const {refresh} = context

function updateRefresh(interval: number) {
const updateRefresh = (interval: number) => {
const status =
interval === 0 ? AutoRefreshStatus.Paused : AutoRefreshStatus.Active

updateTimeContext(id, {
update({
refresh: {
status,
interval,
},
} as TimeBlock)
}

function updateRange(range) {
updateTimeContext(id, {
...timeContext[id],
range,
})
return useMemo(
() => (
<AutoRefreshDropdown
selected={refresh}
onChoose={updateRefresh}
showManualRefresh={false}
/>
),
[refresh]
)
}

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

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

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

return (
<>
<ConnectedTimeZoneDropdown />
<ConnectedTimeRangeDropdown context={timeContext[id]} update={update} />
<ConnectedAutoRefreshDropdown context={timeContext[id]} update={update} />
</>
)
}

const Header: FC = () => {
function submit() {} // eslint-disable-line @typescript-eslint/no-empty-function

return (
Expand All @@ -60,16 +102,7 @@ const Header: FC = () => {
</Page.ControlBarLeft>
<Page.ControlBarRight>
<div className="notebook-header--buttons">
<TimeZoneDropdown
timeZone={timeZone}
onSetTimeZone={onSetTimeZone}
/>
<TimeRangeDropdown timeRange={range} onSetTimeRange={updateRange} />
<AutoRefreshDropdown
selected={refresh}
onChoose={updateRefresh}
showManualRefresh={false}
/>
<EnsureTimeContextExists />
<SubmitQueryButton
submitButtonDisabled={false}
queryStatus={RemoteDataState.NotStarted}
Expand All @@ -82,12 +115,12 @@ const Header: FC = () => {
)
}

export {Header}

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

export {Header}
2 changes: 0 additions & 2 deletions ui/src/notebooks/components/Notebook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {Page} from '@influxdata/clockface'
import {NotebookProvider} from 'src/notebooks/context/notebook'
import Header from 'src/notebooks/components/Header'
import PipeList from 'src/notebooks/components/PipeList'
import NotebookPanel from 'src/notebooks/components/panel/NotebookPanel'

// NOTE: uncommon, but using this to scope the project
// within the page and not bleed it's dependancies outside
Expand All @@ -24,5 +23,4 @@ const NotebookPage: FC = () => {
)
}

export {NotebookPanel}
export default NotebookPage
7 changes: 5 additions & 2 deletions ui/src/notebooks/components/Pipe.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {FC, createElement} from 'react'
import {FC, createElement, useMemo} from 'react'

import {PIPE_DEFINITIONS, PipeProp} from 'src/notebooks'

Expand All @@ -10,7 +10,10 @@ const Pipe: FC<PipeProp> = props => {
return null
}

return createElement(PIPE_DEFINITIONS[data.type].component, props)
return useMemo(
() => createElement(PIPE_DEFINITIONS[data.type].component, props),
[props.data]
)
}

export default Pipe
42 changes: 29 additions & 13 deletions ui/src/notebooks/components/PipeList.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,46 @@
import React, {FC, useContext, createElement} from 'react'
import React, {FC, useContext, useCallback, createElement, useMemo} from 'react'
import {PipeContextProps, PipeData} from 'src/notebooks'
import Pipe from 'src/notebooks/components/Pipe'
import {NotebookContext} from 'src/notebooks/context/notebook'
import NotebookPanel from 'src/notebooks/components/panel/NotebookPanel'

const PipeList: FC = () => {
const {id, pipes, updatePipe} = useContext(NotebookContext)
const _pipes = pipes.map((pipe, index) => {
const panel: FC<PipeContextProps> = props => {
interface NotebookPipeProps {
index: number
data: PipeData
onUpdate: (index: number, pipe: PipeData) => void
}

const NotebookPipe: FC<NotebookPipeProps> = ({index, data, onUpdate}) => {
const panel: FC<PipeContextProps> = useMemo(
() => props => {
const _props = {
...props,
index,
}

return createElement(NotebookPanel, _props)
}
const onUpdate = (data: PipeData) => {
updatePipe(index, data)
}
},
[index]
)

const _onUpdate = (data: PipeData) => {
onUpdate(index, data)
}

return <Pipe data={data} onUpdate={_onUpdate} Context={panel} />
}

const PipeList: FC = () => {
const {id, pipes, updatePipe} = useContext(NotebookContext)
const update = useCallback(updatePipe, [id])

const _pipes = pipes.map((_, index) => {
return (
<Pipe
<NotebookPipe
key={`pipe-${id}-${index}`}
data={pipe}
onUpdate={onUpdate}
Context={panel}
index={index}
data={pipes[index]}
onUpdate={update}
/>
)
})
Expand Down
Loading

0 comments on commit 6e67fb4

Please sign in to comment.