feat(ui/explorer/flux): use flux to determine InfluxDB v2 schema
parent
60c34f9c53
commit
ffa405d738
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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}
|
||||
>
|
||||
|
|
|
@ -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: [],
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue