feat(ui/explorer/flux): use flux to determine InfluxDB v2 schema

pull/5631/head
Pavel Zavora 2020-12-07 19:24:30 +01:00
parent 60c34f9c53
commit ffa405d738
6 changed files with 92 additions and 37 deletions

View File

@ -7,10 +7,29 @@ import showDatabasesParser from 'src/shared/parsing/showDatabases'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Source, NotificationAction} from 'src/types'
import {executeQuery} from 'src/shared/apis/flux/query'
import {parseResponse} from 'src/shared/parsing/flux/response'
interface Props {
source: Source
notify: NotificationAction
v2?: boolean
}
export async function getBuckets(source: Source): Promise<string[]> {
const {csv} = await executeQuery(source, 'buckets()')
const tables = parseResponse(csv)
if (tables && tables.length > 0) {
const data = tables[0].data
if (data.length > 1) {
const nameIndex = data[0].indexOf('name')
if (nameIndex > 0) {
const buckets = data.slice(1).map(arr => arr[nameIndex] as string)
return buckets.sort()
}
}
}
return []
}
interface State {
@ -32,13 +51,16 @@ class DatabaseList extends PureComponent<Props, State> {
}
public async getDatabases() {
const {source} = this.props
const {source, v2} = this.props
try {
const {data} = await showDatabases(source.links.proxy)
const {databases} = showDatabasesParser(data)
const sorted = databases.sort()
this.setState({databases: sorted})
if (v2) {
const buckets = await getBuckets(source)
this.setState({databases: buckets})
} else {
const {data} = await showDatabases(source.links.proxy)
const {databases} = showDatabasesParser(data)
this.setState({databases: databases.sort()})
}
} catch (err) {
console.error(err)
}

View File

@ -19,6 +19,14 @@ interface State {
loading: RemoteDataState
}
export async function fetchFluxMeasurements(
source: Source,
bucket: string
): Promise<string[]> {
const measurementResults = await fetchMeasurementsAsync(source, bucket)
return parseValuesColumn(measurementResults)
}
class FetchMeasurements extends PureComponent<Props, State> {
constructor(props) {
super(props)
@ -39,8 +47,7 @@ class FetchMeasurements extends PureComponent<Props, State> {
const {source, bucket} = this.props
this.setState({loading: RemoteDataState.Loading})
try {
const measurementResults = await fetchMeasurementsAsync(source, bucket)
const measurements = parseValuesColumn(measurementResults)
const measurements = await fetchFluxMeasurements(source, bucket)
this.setState({measurements, loading: RemoteDataState.Done})
} catch (error) {
this.setState({loading: RemoteDataState.Error})

View File

@ -7,15 +7,16 @@ import {Source, NotificationAction} from 'src/types'
interface Props {
source: Source
notify: NotificationAction
v2?: boolean
}
class SchemaExplorer extends PureComponent<Props> {
public render() {
const {source, notify} = this.props
const {source, notify, v2} = this.props
return (
<div className="flux-schema-explorer">
<FancyScrollbar>
<DatabaseList source={source} notify={notify} />
<DatabaseList source={source} notify={notify} v2={v2} />
</FancyScrollbar>
</div>
)

View File

@ -12,7 +12,7 @@ import {Button, ComponentSize, ComponentColor} from 'src/reusable_ui'
import FluxFunctionsToolbar from 'src/flux/components/flux_functions_toolbar/FluxFunctionsToolbar'
// Constants
import {HANDLE_VERTICAL} from 'src/shared/constants'
import {HANDLE_VERTICAL, SOURCE_TYPE_INFLUX_V2} from 'src/shared/constants'
// Utils
import {getAST} from 'src/shared/apis/flux/ast'
@ -90,6 +90,7 @@ class FluxQueryMaker extends PureComponent<Props, State> {
const {suggestions, isWizardActive, draftScriptStatus} = this.state
const [leftSize, middleSize, rightSize] = fluxProportions
const v2 = source.type === SOURCE_TYPE_INFLUX_V2
const divisions = [
{
@ -97,7 +98,9 @@ class FluxQueryMaker extends PureComponent<Props, State> {
size: leftSize,
headerButtons: [],
menuOptions: [],
render: () => <SchemaExplorer source={source} notify={notify} />,
render: () => (
<SchemaExplorer source={source} notify={notify} v2={v2} />
),
headerOrientation: HANDLE_VERTICAL,
},
{
@ -152,6 +155,7 @@ class FluxQueryMaker extends PureComponent<Props, State> {
<FluxScriptWizard
source={source}
isWizardActive={isWizardActive}
v2={v2}
onSetIsWizardActive={this.handleSetIsWizardActive}
onAddToScript={this.handleAddToScript}
>

View File

@ -33,6 +33,10 @@ import {
// Types
import {RemoteDataState, Source} from 'src/types'
import {getBuckets} from 'src/flux/components/DatabaseList'
import {fetchFluxMeasurements} from 'src/flux/components/FetchMeasurements'
import {fieldsByMeasurement} from 'src/shared/apis/flux/metaQueries'
import {parseFieldsByMeasurements} from 'src/shared/parsing/flux/values'
// These constants are selected so that the dropdown menus will not overflow
// out of the `.flux-script-wizard--wizard` window
@ -45,6 +49,7 @@ interface Props {
isWizardActive: boolean
onSetIsWizardActive: (isWizardActive: boolean) => void
onAddToScript: (script: string) => void
v2?: boolean
}
interface State {
@ -86,13 +91,6 @@ class FluxScriptWizard extends PureComponent<Props, State> {
public render() {
const {children, isWizardActive} = this.props
const {
measurements,
fields,
selectedMeasurement,
selectedFields,
selectedAggFunction,
} = this.state
if (!isWizardActive) {
return (
@ -101,6 +99,13 @@ class FluxScriptWizard extends PureComponent<Props, State> {
</div>
)
}
const {
measurements,
fields,
selectedMeasurement,
selectedFields,
selectedAggFunction,
} = this.state
return (
<div className="flux-script-wizard">
@ -249,11 +254,9 @@ class FluxScriptWizard extends PureComponent<Props, State> {
}
private get buttonStatus(): ComponentStatus {
const {selectedDB, selectedRP, selectedMeasurement} = this.state
const {selectedDB, selectedMeasurement} = this.state
const needsSelection = [selectedDB, selectedRP, selectedMeasurement].some(
isEmpty
)
const needsSelection = [selectedDB, selectedMeasurement].some(isEmpty)
const buttonStatus = needsSelection
? ComponentStatus.Disabled
@ -304,7 +307,7 @@ class FluxScriptWizard extends PureComponent<Props, State> {
}
private fetchAndSetDBsToRPs = async () => {
const {source} = this.props
const {source, v2} = this.props
this.setState({
dbsToRPs: {},
@ -322,7 +325,15 @@ class FluxScriptWizard extends PureComponent<Props, State> {
let dbsToRPs
try {
dbsToRPs = await this.fetchDBsToRPs(source.links.proxy)
if (v2) {
const buckets = await getBuckets(source)
dbsToRPs = buckets.reduce((acc, db) => {
acc[db] = ['']
return acc
}, {})
} else {
dbsToRPs = await this.fetchDBsToRPs(source.links.proxy)
}
} catch {
this.setState({dbsToRPsStatus: RemoteDataState.Error})
@ -343,7 +354,7 @@ class FluxScriptWizard extends PureComponent<Props, State> {
}
private fetchAndSetMeasurements = async () => {
const {source} = this.props
const {source, v2} = this.props
const {selectedDB} = this.state
this.setState({
@ -358,10 +369,14 @@ class FluxScriptWizard extends PureComponent<Props, State> {
let measurements
try {
measurements = await this.fetchMeasurements(
source.links.proxy,
selectedDB
)
if (v2) {
measurements = await fetchFluxMeasurements(source, selectedDB)
} else {
measurements = await this.fetchMeasurements(
source.links.proxy,
selectedDB
)
}
} catch {
this.setState({
measurements: [],
@ -383,7 +398,7 @@ class FluxScriptWizard extends PureComponent<Props, State> {
}
private fetchAndSetFields = async () => {
const {source} = this.props
const {source, v2} = this.props
const {selectedDB, selectedMeasurement} = this.state
this.setState({
@ -395,11 +410,17 @@ class FluxScriptWizard extends PureComponent<Props, State> {
let fields
try {
fields = await this.fetchFields(
source.links.proxy,
selectedDB,
selectedMeasurement
)
if (v2) {
const fieldsResults = await fieldsByMeasurement(source, selectedDB)
const {fieldsByMeasurements} = parseFieldsByMeasurements(fieldsResults)
fields = fieldsByMeasurements[selectedMeasurement] || []
} else {
fields = await this.fetchFields(
source.links.proxy,
selectedDB,
selectedMeasurement
)
}
} catch {
this.setState({
fields: [],

View File

@ -62,7 +62,7 @@ export async function fetchFields(
}
export function formatDBwithRP(db: string, rp: string): string {
return `${db}/${rp}`
return rp ? `${db}/${rp}` : `${db}`
}
export function toComponentStatus(