Merge pull request #5746 from influxdata/5745/write_data_v2

feat(ui/explorer): use v2 write API with buckets when Flux tab is selected
pull/5748/head
Pavel Závora 2021-05-06 05:55:50 +02:00 committed by GitHub
commit ceef251ab6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 109 additions and 45 deletions

View File

@ -20,6 +20,7 @@
1. [#5726](https://github.com/influxdata/chronograf/pull/5726): Allow to setup InfluxDB v2 connection from chronograf command-line.
1. [#5735](https://github.com/influxdata/chronograf/pull/5735): Allow to add custom auto-refresh intervals.
1. [#5737](https://github.com/influxdata/chronograf/pull/5737): Allow to send multiple queries to dashboard.
1. [#5746](https://github.com/influxdata/chronograf/pull/5746): Write to buckets when Flux tab is selected.
### Bug Fixes

View File

@ -120,8 +120,19 @@ func (s *Service) Write(w http.ResponseWriter, r *http.Request) {
Error(w, http.StatusUnprocessableEntity, msg, s.Logger)
return
}
query := r.URL.Query()
version := query.Get("v")
query.Del("v")
if strings.HasPrefix(version, "2") {
u.Path = "/api/v2/write"
// v2 organization name is stored in username (org does not matter against v1)
query.Set("org", src.Username)
query.Set("bucket", query.Get("db"))
query.Del("db")
} else {
u.Path = "/write"
u.RawQuery = r.URL.RawQuery
}
u.RawQuery = query.Encode()
director := func(req *http.Request) {
// Set the Host header of the original source URL

View File

@ -495,15 +495,15 @@ func paramID(key string, r *http.Request) (int, error) {
return id, nil
}
func paramInt64(key string, r *http.Request) (int64, error) {
ctx := r.Context()
param := httprouter.GetParamFromContext(ctx, key)
v, err := strconv.ParseInt(param, 10, 64)
if err != nil {
return -1, fmt.Errorf("Error converting parameter %s", param)
}
return v, nil
}
// func paramInt64(key string, r *http.Request) (int64, error) {
// ctx := r.Context()
// param := httprouter.GetParamFromContext(ctx, key)
// v, err := strconv.ParseInt(param, 10, 64)
// if err != nil {
// return -1, fmt.Errorf("Error converting parameter %s", param)
// }
// return v, nil
// }
func paramStr(key string, r *http.Request) (string, error) {
ctx := r.Context()

View File

@ -12,13 +12,18 @@ export const writeLineProtocolAsync = (
source: Source,
db: string,
data: string,
precision?: string
precision?: string,
v2?: boolean
) => async (dispatch): Promise<void> => {
try {
await writeLineProtocolAJAX(source, db, data, precision)
await writeLineProtocolAJAX(source, db, data, precision, v2)
dispatch(notify(notifyDataWritten()))
} catch (response) {
dispatch(notify(notifyDataWriteFailed(response.data.error)))
dispatch(
notify(
notifyDataWriteFailed(response.data?.error || response.data?.message)
)
)
throw response
}
}

View File

@ -5,10 +5,11 @@ export const writeLineProtocol = async (
source: Source,
db: string,
data: string,
precision?: string
precision?: string,
v2?: boolean
): Promise<void> => {
const url = `${source.links.write}?db=${db}&precision=${
precision ? precision : 'ns'
}`
}${v2 ? '&v=2' : ''}`
await AJAX({url, method: 'POST', data})
}

View File

@ -22,11 +22,13 @@ interface Props {
selectedDatabase: string
onClose: () => void
errorThrown: () => void
useV2: boolean
writeLineProtocol: (
source: Source,
database: string,
content: string,
precision?: string
precision?: string,
useV2?: boolean
) => void
}
@ -62,7 +64,7 @@ class WriteDataForm extends PureComponent<Props, State> {
}
public render() {
const {onClose, errorThrown, source} = this.props
const {onClose, errorThrown, source, useV2} = this.props
const {dragClass} = this.state
return (
@ -81,6 +83,7 @@ class WriteDataForm extends PureComponent<Props, State> {
onClose={onClose}
errorThrown={errorThrown}
onToggleMode={this.handleToggleMode}
useBuckets={useV2}
handlePrecisionChange={this.handlePrecisionChange}
handleSelectDatabase={this.handleSelectDatabase}
/>
@ -119,7 +122,7 @@ class WriteDataForm extends PureComponent<Props, State> {
}
private handleSubmit = async () => {
const {onClose, source, writeLineProtocol} = this.props
const {onClose, source, writeLineProtocol, useV2} = this.props
const {
inputContent,
uploadContent,
@ -135,13 +138,19 @@ class WriteDataForm extends PureComponent<Props, State> {
this.setState({isUploading: true})
try {
await writeLineProtocol(source, selectedDatabase, content, precision)
await writeLineProtocol(
source,
selectedDatabase,
content,
precision,
useV2
)
this.setState({isUploading: false})
onClose()
window.location.reload()
} catch (error) {
this.setState({isUploading: false})
console.error(error.data.error)
console.error(error.data)
}
}

View File

@ -15,6 +15,7 @@ interface Props {
onClose: () => void
mode: string
source: Source
useBuckets: boolean
}
class WriteDataHeader extends PureComponent<Props> {
@ -26,6 +27,7 @@ class WriteDataHeader extends PureComponent<Props> {
onClose,
source,
precision,
useBuckets,
} = this.props
return (
@ -36,6 +38,7 @@ class WriteDataHeader extends PureComponent<Props> {
source={source}
onSelectDatabase={handleSelectDatabase}
database={selectedDatabase}
useBuckets={useBuckets}
onErrorThrown={errorThrown}
/>
{this.modeSelector}

View File

@ -297,7 +297,7 @@ export class DataExplorer extends PureComponent<Props, State> {
}
private get writeDataForm(): JSX.Element {
const {source, errorThrownAction, writeLineProtocol} = this.props
const {source, errorThrownAction, writeLineProtocol, queryType} = this.props
const {isWriteFormVisible} = this.state
return (
@ -308,6 +308,7 @@ export class DataExplorer extends PureComponent<Props, State> {
selectedDatabase={this.selectedDatabase}
onClose={this.handleCloseWriteData}
writeLineProtocol={writeLineProtocol}
useV2={queryType === 'flux'}
/>
</OverlayTechnology>
)

View File

@ -5,6 +5,7 @@ import {showDatabases} from 'src/shared/apis/metaQuery'
import parsers from 'src/shared/parsing'
import {Source} from 'src/types/sources'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {getBuckets} from 'src/flux/components/DatabaseList'
const {databases: showDatabasesParser} = parsers
interface Database {
@ -17,10 +18,12 @@ interface Props {
onStartEdit?: () => void
onErrorThrown: (error: string) => void
source: Source
// true loads buckets in place of databases
useBuckets?: boolean
}
interface State {
databases: Database[]
databases: string[]
}
@ErrorHandling
@ -58,16 +61,50 @@ class DatabaseDropdown extends Component<Props, State> {
}
private getDatabasesAsync = async (): Promise<void> => {
const {source, database, onSelectDatabase, onErrorThrown} = this.props
const proxy = source.links.proxy
const {
source,
database,
onSelectDatabase,
onErrorThrown,
useBuckets,
} = this.props
let databases: string[]
if (useBuckets) {
try {
const {data} = await showDatabases(proxy)
const {databases, errors} = showDatabasesParser(data)
if (errors.length > 0) {
throw errors[0] // only one error can come back from this, but it's returned as an array
databases = await getBuckets(source)
databases.sort((a, b) => {
// databases starting with '_' are the last
if (b.startsWith('_')) {
if (a.startsWith('_')) {
return a.localeCompare(b)
}
const nonSystemDatabases = databases.filter(name => name !== '_internal')
return -1
}
return a.localeCompare(b)
})
} catch (e) {
console.error(e)
onErrorThrown(e)
return
}
} else {
try {
const proxy = source.links.proxy
const {data} = await showDatabases(proxy)
const parserResult = showDatabasesParser(data)
if (parserResult.errors.length > 0) {
throw parserResult.errors[0] // only one error can come back from this, but it's returned as an array
}
databases = parserResult.databases
} catch (error) {
console.error(error)
onErrorThrown(error)
return
}
}
const nonSystemDatabases = databases.filter(
name => !name.startsWith('_internal')
)
this.setState({
databases: nonSystemDatabases,
@ -78,10 +115,6 @@ class DatabaseDropdown extends Component<Props, State> {
onSelectDatabase({
text: selectedDatabaseText,
})
} catch (error) {
console.error(error)
onErrorThrown(error)
}
}
}