Merge pull request #5746 from influxdata/5745/write_data_v2
feat(ui/explorer): use v2 write API with buckets when Flux tab is selectedpull/5748/head
commit
ceef251ab6
|
@ -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
|
||||
|
||||
|
|
|
@ -120,8 +120,19 @@ func (s *Service) Write(w http.ResponseWriter, r *http.Request) {
|
|||
Error(w, http.StatusUnprocessableEntity, msg, s.Logger)
|
||||
return
|
||||
}
|
||||
u.Path = "/write"
|
||||
u.RawQuery = r.URL.RawQuery
|
||||
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 = query.Encode()
|
||||
|
||||
director := func(req *http.Request) {
|
||||
// Set the Host header of the original source URL
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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,30 +61,60 @@ class DatabaseDropdown extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private getDatabasesAsync = async (): Promise<void> => {
|
||||
const {source, database, onSelectDatabase, onErrorThrown} = this.props
|
||||
const proxy = source.links.proxy
|
||||
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
|
||||
const {
|
||||
source,
|
||||
database,
|
||||
onSelectDatabase,
|
||||
onErrorThrown,
|
||||
useBuckets,
|
||||
} = this.props
|
||||
let databases: string[]
|
||||
if (useBuckets) {
|
||||
try {
|
||||
databases = await getBuckets(source)
|
||||
databases.sort((a, b) => {
|
||||
// databases starting with '_' are the last
|
||||
if (b.startsWith('_')) {
|
||||
if (a.startsWith('_')) {
|
||||
return a.localeCompare(b)
|
||||
}
|
||||
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 !== '_internal')
|
||||
|
||||
this.setState({
|
||||
databases: nonSystemDatabases,
|
||||
})
|
||||
const selectedDatabaseText = nonSystemDatabases.includes(database)
|
||||
? database
|
||||
: nonSystemDatabases[0] || 'No databases'
|
||||
onSelectDatabase({
|
||||
text: selectedDatabaseText,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
onErrorThrown(error)
|
||||
}
|
||||
const nonSystemDatabases = databases.filter(
|
||||
name => !name.startsWith('_internal')
|
||||
)
|
||||
|
||||
this.setState({
|
||||
databases: nonSystemDatabases,
|
||||
})
|
||||
const selectedDatabaseText = nonSystemDatabases.includes(database)
|
||||
? database
|
||||
: nonSystemDatabases[0] || 'No databases'
|
||||
onSelectDatabase({
|
||||
text: selectedDatabaseText,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue