feat: add query type for notebooks (#18168)
parent
78466ba736
commit
6e67fb4f6f
|
|
@ -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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -135,7 +136,8 @@ 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)
|
||||
|
|
@ -143,13 +145,22 @@ export class LSPServer {
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -157,14 +168,6 @@ export class LSPServer {
|
|||
}
|
||||
}
|
||||
|
||||
updateBuckets(buckets: string[]) {
|
||||
this.buckets = buckets
|
||||
}
|
||||
|
||||
setOrg(orgID: string) {
|
||||
this.orgID = orgID
|
||||
}
|
||||
|
||||
initialize() {
|
||||
return this.send(initialize(this.currentMessageID))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -14,25 +14,34 @@ 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])
|
||||
}
|
||||
|
||||
function updateRefresh(interval: number) {
|
||||
const ConnectedAutoRefreshDropdown = ({context, update}) => {
|
||||
const {refresh} = context
|
||||
|
||||
const updateRefresh = (interval: number) => {
|
||||
const status =
|
||||
interval === 0 ? AutoRefreshStatus.Paused : AutoRefreshStatus.Active
|
||||
|
||||
updateTimeContext(id, {
|
||||
update({
|
||||
refresh: {
|
||||
status,
|
||||
interval,
|
||||
|
|
@ -40,13 +49,46 @@ const Header: FC = () => {
|
|||
} 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 (
|
||||
|
|
@ -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}
|
||||
|
|
@ -82,8 +115,6 @@ const Header: FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export {Header}
|
||||
|
||||
export default () => (
|
||||
<TimeProvider>
|
||||
<AppSettingProvider>
|
||||
|
|
@ -91,3 +122,5 @@ export default () => (
|
|||
</AppSettingProvider>
|
||||
</TimeProvider>
|
||||
)
|
||||
|
||||
export {Header}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -24,5 +23,4 @@ const NotebookPage: FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export {NotebookPanel}
|
||||
export default NotebookPage
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {FC, createElement} from 'react'
|
||||
import {FC, createElement, useMemo} from 'react'
|
||||
|
||||
import {PIPE_DEFINITIONS, PipeProp} from 'src/notebooks'
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Libraries
|
||||
import React, {FC, useContext} from 'react'
|
||||
import React, {FC, useContext, useCallback} from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components
|
||||
|
|
@ -20,15 +20,57 @@ export interface Props extends PipeContextProps {
|
|||
index: number
|
||||
}
|
||||
|
||||
const NotebookPanel: FC<Props> = ({index, children}) => {
|
||||
const {pipes, removePipe, movePipe, meta} = useContext(NotebookContext)
|
||||
export interface HeaderProps {
|
||||
index: number
|
||||
}
|
||||
|
||||
const NotebookPanelHeader: FC<HeaderProps> = ({index}) => {
|
||||
const {pipes, removePipe, movePipe} = useContext(NotebookContext)
|
||||
const canBeMovedUp = index > 0
|
||||
const canBeMovedDown = index < pipes.length - 1
|
||||
const canBeRemoved = index !== 0
|
||||
|
||||
const moveUp = canBeMovedUp ? () => movePipe(index, index - 1) : null
|
||||
const moveDown = canBeMovedDown ? () => movePipe(index, index + 1) : null
|
||||
const remove = canBeRemoved ? () => removePipe(index) : null
|
||||
const moveUp = useCallback(
|
||||
canBeMovedUp ? () => movePipe(index, index - 1) : null,
|
||||
[index, pipes]
|
||||
)
|
||||
const moveDown = useCallback(
|
||||
canBeMovedDown ? () => movePipe(index, index + 1) : null,
|
||||
[index, pipes]
|
||||
)
|
||||
const remove = useCallback(canBeRemoved ? () => removePipe(index) : null, [
|
||||
index,
|
||||
pipes,
|
||||
])
|
||||
|
||||
return (
|
||||
<div className="notebook-panel--header">
|
||||
<FlexBox
|
||||
className="notebook-panel--header-left"
|
||||
alignItems={AlignItems.Center}
|
||||
margin={ComponentSize.Small}
|
||||
justifyContent={JustifyContent.FlexStart}
|
||||
>
|
||||
<NotebookPanelTitle index={index} />
|
||||
</FlexBox>
|
||||
<FlexBox
|
||||
className="notebook-panel--header-right"
|
||||
alignItems={AlignItems.Center}
|
||||
margin={ComponentSize.Small}
|
||||
justifyContent={JustifyContent.FlexEnd}
|
||||
>
|
||||
<MovePanelButton direction="up" onClick={moveUp} />
|
||||
<MovePanelButton direction="down" onClick={moveDown} />
|
||||
<PanelVisibilityToggle index={index} />
|
||||
<RemovePanelButton onRemove={remove} />
|
||||
</FlexBox>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const NotebookPanel: FC<Props> = props => {
|
||||
const {index, children} = props
|
||||
const {meta} = useContext(NotebookContext)
|
||||
|
||||
const isVisible = meta[index].visible
|
||||
|
||||
|
|
@ -39,28 +81,8 @@ const NotebookPanel: FC<Props> = ({index, children}) => {
|
|||
|
||||
return (
|
||||
<div className={panelClassName}>
|
||||
<div className="notebook-panel--header">
|
||||
<FlexBox
|
||||
className="notebook-panel--header-left"
|
||||
alignItems={AlignItems.Center}
|
||||
margin={ComponentSize.Small}
|
||||
justifyContent={JustifyContent.FlexStart}
|
||||
>
|
||||
<NotebookPanelTitle index={index} />
|
||||
</FlexBox>
|
||||
<FlexBox
|
||||
className="notebook-panel--header-right"
|
||||
alignItems={AlignItems.Center}
|
||||
margin={ComponentSize.Small}
|
||||
justifyContent={JustifyContent.FlexEnd}
|
||||
>
|
||||
<MovePanelButton direction="up" onClick={moveUp} />
|
||||
<MovePanelButton direction="down" onClick={moveDown} />
|
||||
<PanelVisibilityToggle index={index} />
|
||||
<RemovePanelButton onRemove={remove} />
|
||||
</FlexBox>
|
||||
</div>
|
||||
<div className="notebook-panel--body">{isVisible && children}</div>
|
||||
<NotebookPanelHeader index={index} />
|
||||
<div className="notebook-panel--body">{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,22 +30,20 @@ export const AppSettingContext = React.createContext<AppSettingContextType>(
|
|||
DEFAULT_CONTEXT
|
||||
)
|
||||
|
||||
export const AppSettingProvider: FC<Props> = ({
|
||||
timeZone,
|
||||
onSetTimeZone,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<AppSettingContext.Provider
|
||||
value={{
|
||||
timeZone,
|
||||
onSetTimeZone,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AppSettingContext.Provider>
|
||||
)
|
||||
}
|
||||
export const AppSettingProvider: FC<Props> = React.memo(
|
||||
({timeZone, onSetTimeZone, children}) => {
|
||||
return (
|
||||
<AppSettingContext.Provider
|
||||
value={{
|
||||
timeZone,
|
||||
onSetTimeZone,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AppSettingContext.Provider>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {FC, useState} from 'react'
|
||||
import React, {FC, useState, useCallback} from 'react'
|
||||
import {PipeData} from 'src/notebooks'
|
||||
|
||||
export interface PipeMeta {
|
||||
|
|
@ -49,68 +49,86 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
const [pipes, setPipes] = useState(DEFAULT_CONTEXT.pipes)
|
||||
const [meta, setMeta] = useState(DEFAULT_CONTEXT.meta)
|
||||
|
||||
function addPipe(pipe: PipeData) {
|
||||
const add = data => {
|
||||
return pipes => {
|
||||
pipes.push(data)
|
||||
const _setPipes = useCallback(setPipes, [id])
|
||||
const _setMeta = useCallback(setMeta, [id])
|
||||
|
||||
const addPipe = useCallback(
|
||||
(pipe: PipeData) => {
|
||||
const add = data => {
|
||||
return pipes => {
|
||||
pipes.push(data)
|
||||
return pipes.slice()
|
||||
}
|
||||
}
|
||||
_setPipes(add(pipe))
|
||||
_setMeta(
|
||||
add({
|
||||
title: `Notebook_${++GENERATOR_INDEX}`,
|
||||
visible: true,
|
||||
})
|
||||
)
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
const updatePipe = useCallback(
|
||||
(idx: number, pipe: PipeData) => {
|
||||
_setPipes(pipes => {
|
||||
pipes[idx] = {
|
||||
...pipes[idx],
|
||||
...pipe,
|
||||
}
|
||||
return pipes.slice()
|
||||
})
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
const updateMeta = useCallback(
|
||||
(idx: number, pipe: PipeMeta) => {
|
||||
_setMeta(pipes => {
|
||||
pipes[idx] = {
|
||||
...pipes[idx],
|
||||
...pipe,
|
||||
}
|
||||
return pipes.slice()
|
||||
})
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
const movePipe = useCallback(
|
||||
(currentIdx: number, newIdx: number) => {
|
||||
const move = list => {
|
||||
const idx = ((newIdx % list.length) + list.length) % list.length
|
||||
|
||||
if (idx === currentIdx) {
|
||||
return list
|
||||
}
|
||||
|
||||
const pipe = list.splice(currentIdx, 1)
|
||||
|
||||
list.splice(idx, 0, pipe[0])
|
||||
|
||||
return list.slice()
|
||||
}
|
||||
_setPipes(move)
|
||||
_setMeta(move)
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
const removePipe = useCallback(
|
||||
(idx: number) => {
|
||||
const remove = pipes => {
|
||||
pipes.splice(idx, 1)
|
||||
return pipes.slice()
|
||||
}
|
||||
}
|
||||
setPipes(add(pipe))
|
||||
setMeta(
|
||||
add({
|
||||
title: `Notebook_${++GENERATOR_INDEX}`,
|
||||
visible: true,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function updatePipe(idx: number, pipe: PipeData) {
|
||||
setPipes(pipes => {
|
||||
pipes[idx] = {
|
||||
...pipes[idx],
|
||||
...pipe,
|
||||
}
|
||||
return pipes.slice()
|
||||
})
|
||||
}
|
||||
|
||||
function updateMeta(idx: number, pipe: PipeMeta) {
|
||||
setMeta(pipes => {
|
||||
pipes[idx] = {
|
||||
...pipes[idx],
|
||||
...pipe,
|
||||
}
|
||||
return pipes.slice()
|
||||
})
|
||||
}
|
||||
|
||||
function movePipe(currentIdx: number, newIdx: number) {
|
||||
const move = list => {
|
||||
const idx = ((newIdx % list.length) + list.length) % list.length
|
||||
|
||||
if (idx === currentIdx) {
|
||||
return list
|
||||
}
|
||||
|
||||
const pipe = list.splice(currentIdx, 1)
|
||||
|
||||
list.splice(idx, 0, pipe[0])
|
||||
|
||||
return list.slice()
|
||||
}
|
||||
setPipes(move)
|
||||
setMeta(move)
|
||||
}
|
||||
|
||||
function removePipe(idx: number) {
|
||||
const remove = pipes => {
|
||||
pipes.splice(idx, 1)
|
||||
return pipes.slice()
|
||||
}
|
||||
setPipes(remove)
|
||||
setMeta(remove)
|
||||
}
|
||||
_setPipes(remove)
|
||||
_setMeta(remove)
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
return (
|
||||
<NotebookContext.Provider
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {FC, useState} from 'react'
|
||||
import React, {FC, useState, useCallback} from 'react'
|
||||
import {AutoRefresh, TimeRange} from 'src/types'
|
||||
import {DEFAULT_TIME_RANGE} from 'src/shared/constants/timeRanges'
|
||||
import {AUTOREFRESH_DEFAULT} from 'src/shared/constants'
|
||||
|
|
@ -36,7 +36,7 @@ export const TimeContext = React.createContext<TimeContext>(DEFAULT_CONTEXT)
|
|||
export const TimeProvider: FC = ({children}) => {
|
||||
const [timeContext, setTimeContext] = useState({})
|
||||
|
||||
function addTimeContext(id: string, block?: TimeBlock) {
|
||||
const addTimeContext = useCallback((id: string, block?: TimeBlock) => {
|
||||
setTimeContext(ranges => {
|
||||
if (ranges.hasOwnProperty(id)) {
|
||||
throw new Error(
|
||||
|
|
@ -50,9 +50,9 @@ export const TimeProvider: FC = ({children}) => {
|
|||
[id]: {...(block || DEFAULT_STATE)},
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
function updateTimeContext(id: string, block: TimeBlock) {
|
||||
const updateTimeContext = useCallback((id: string, block: TimeBlock) => {
|
||||
setTimeContext(ranges => {
|
||||
return {
|
||||
...ranges,
|
||||
|
|
@ -62,9 +62,9 @@ export const TimeProvider: FC = ({children}) => {
|
|||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
function removeTimeContext(id: string) {
|
||||
const removeTimeContext = useCallback((id: string) => {
|
||||
setTimeContext(ranges => {
|
||||
if (!ranges.hasOwnProperty(id)) {
|
||||
throw new Error(`TimeContext[${id}] doesn't exist`)
|
||||
|
|
@ -73,7 +73,7 @@ export const TimeProvider: FC = ({children}) => {
|
|||
delete ranges[id]
|
||||
return {...ranges}
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<TimeContext.Provider
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import {register} from 'src/notebooks'
|
||||
import View from './view'
|
||||
import './style.scss'
|
||||
|
||||
register({
|
||||
type: 'query',
|
||||
component: View,
|
||||
button: 'Custom Script',
|
||||
initial: {
|
||||
activeQuery: 0,
|
||||
queries: [
|
||||
{
|
||||
text: '',
|
||||
editMode: 'advanced',
|
||||
builderConfig: {
|
||||
buckets: [],
|
||||
tags: [],
|
||||
functions: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.notebook-query {
|
||||
height: 300px;
|
||||
position: relative;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
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}) => {
|
||||
const {queries, activeQuery} = data
|
||||
const query = queries[activeQuery]
|
||||
|
||||
function updateText(text) {
|
||||
const _queries = queries.slice()
|
||||
_queries[activeQuery] = {
|
||||
...queries[activeQuery],
|
||||
text,
|
||||
}
|
||||
|
||||
onUpdate({queries: _queries})
|
||||
}
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<Context>
|
||||
<FluxMonacoEditor
|
||||
script={query.text}
|
||||
onChangeScript={updateText}
|
||||
onSubmitScript={() => {}}
|
||||
/>
|
||||
</Context>
|
||||
),
|
||||
[query.text]
|
||||
)
|
||||
}
|
||||
|
||||
export default Query
|
||||
|
|
@ -143,6 +143,7 @@ $notebook-divider-height: ($cf-marg-a * 2) + $cf-border;
|
|||
padding-top: 0;
|
||||
// flex: 1 0 0;
|
||||
position: relative;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
// Special styling for query builder inside notebook panel
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
// Libraries
|
||||
import {FC} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import {AppState, Bucket, ResourceType} from 'src/types'
|
||||
import {getAll} from 'src/resources/selectors'
|
||||
import {getOrg} from 'src/organizations/selectors'
|
||||
|
||||
import loadServer from 'src/external/monaco.flux.server'
|
||||
|
||||
const FluxBucketProvider: FC<{}> = () => {
|
||||
return null
|
||||
}
|
||||
|
||||
const mstp = (state: AppState): {} => {
|
||||
const buckets = getAll<Bucket>(state, ResourceType.Buckets)
|
||||
const org = getOrg(state)
|
||||
|
||||
loadServer().then(server => {
|
||||
server.updateBuckets(buckets.map(b => b.name))
|
||||
server.setOrg(org.id || '')
|
||||
})
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
export default connect<{}, {}>(
|
||||
mstp,
|
||||
null
|
||||
)(FluxBucketProvider)
|
||||
|
|
@ -4,8 +4,6 @@ import {ProtocolToMonacoConverter} from 'monaco-languageclient/lib/monaco-conver
|
|||
|
||||
// Components
|
||||
import MonacoEditor from 'react-monaco-editor'
|
||||
import FluxBucketProvider from 'src/shared/components/FluxBucketProvider'
|
||||
import GetResources from 'src/resources/components/GetResources'
|
||||
|
||||
// Utils
|
||||
import FLUXLANGID from 'src/external/monaco.flux.syntax'
|
||||
|
|
@ -16,7 +14,7 @@ import {isFlagEnabled} from 'src/shared/utils/featureFlag'
|
|||
|
||||
// Types
|
||||
import {OnChangeScript} from 'src/types/flux'
|
||||
import {EditorType, ResourceType} from 'src/types'
|
||||
import {EditorType} from 'src/types'
|
||||
|
||||
import './FluxMonacoEditor.scss'
|
||||
import {editor as monacoEditor} from 'monaco-editor'
|
||||
|
|
@ -103,9 +101,6 @@ const FluxEditorMonaco: FC<Props> = ({
|
|||
|
||||
return (
|
||||
<div className="flux-editor--monaco" data-testid="flux-editor">
|
||||
<GetResources resources={[ResourceType.Buckets]}>
|
||||
<FluxBucketProvider />
|
||||
</GetResources>
|
||||
<MonacoEditor
|
||||
language={FLUXLANGID}
|
||||
theme={THEME_NAME}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ interface StateProps {
|
|||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onSetActiveQueryText: typeof setActiveQueryText
|
||||
onSubmitQueries: typeof saveAndExecuteQueries
|
||||
onSetActiveQueryText: typeof setActiveQueryText | ((text: string) => void)
|
||||
onSubmitQueries: typeof saveAndExecuteQueries | (() => void)
|
||||
}
|
||||
|
||||
type Props = StateProps & DispatchProps
|
||||
|
|
@ -160,6 +160,8 @@ const TimeMachineFluxEditor: FC<Props> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export {TimeMachineFluxEditor}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const activeQueryText = getActiveQuery(state).text
|
||||
const {activeTab} = getActiveTimeMachine(state)
|
||||
|
|
|
|||
Loading…
Reference in New Issue