Merge pull request #1809 from influxdata/dataloader/line-protocol-precision

Dataloader/line protocol precision
pull/10616/head
Deniz Kusefoglu 2018-12-10 12:56:22 -08:00 committed by GitHub
commit 5dd9912d00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 310 additions and 108 deletions

View File

@ -560,15 +560,7 @@ paths:
name: precision
description: specifies the precision for the unix timestamps within the body line-protocol
schema:
type: string
default: ns
description: specifies the unit of time
enum:
- ns
- us
- u
- ms
- s
$ref: "#/components/schemas/WritePrecision"
responses:
'204':
description: write data is correctly formatted and accepted for writing to the bucket.
@ -3972,6 +3964,14 @@ components:
description: err is a stack of errors that occurred during processing of the request. Useful for debugging.
type: string
required: [code, message, op, err]
WritePrecision:
type: string
enum:
- ms
- s
- us
- u
- ns
LineProtocolError:
properties:
code:

View File

@ -2506,12 +2506,6 @@ export interface Task {
* @memberof Task
*/
cron?: string;
/**
* How long to wait before running the task
* @type {string}
* @memberof Task
*/
offset?: string;
/**
* A simple task repetition schedule; parsed from Flux.
* @type {string}
@ -2542,6 +2536,12 @@ export interface Task {
* @memberof Task
*/
name: string;
/**
* How long to wait before running the task
* @type {string}
* @memberof Task
*/
offset?: string;
/**
* The ID of the organization that owns this Task.
* @type {string}
@ -4801,6 +4801,19 @@ export interface Views {
views?: Array<View>;
}
/**
*
* @export
* @enum {string}
*/
export enum WritePrecision {
Ms = 'ms',
S = 's',
Us = 'us',
U = 'u',
Ns = 'ns'
}
/**
* AuthorizationsApi - axios parameter creator
@ -16668,11 +16681,11 @@ export const WriteApiAxiosParamCreator = function (configuration?: Configuration
* @param {'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow'} [contentType] Content-Type is used to indicate the format of the data sent to the server.
* @param {number} [contentLength] Content-Length is an entity header is indicating the size of the entity-body, in bytes, sent to the database. If the length is greater than the database max body configuration option, a 413 response is sent.
* @param {'application/json'} [accept] specifies the return content format.
* @param {'ns' | 'us' | 'u' | 'ms' | 's'} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {WritePrecision} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: 'ns' | 'us' | 'u' | 'ms' | 's', options: any = {}): RequestArgs {
writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: WritePrecision, options: any = {}): RequestArgs {
// verify required parameter 'org' is not null or undefined
if (org === null || org === undefined) {
throw new RequiredError('org','Required parameter org was null or undefined when calling writePost.');
@ -16756,11 +16769,11 @@ export const WriteApiFp = function(configuration?: Configuration) {
* @param {'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow'} [contentType] Content-Type is used to indicate the format of the data sent to the server.
* @param {number} [contentLength] Content-Length is an entity header is indicating the size of the entity-body, in bytes, sent to the database. If the length is greater than the database max body configuration option, a 413 response is sent.
* @param {'application/json'} [accept] specifies the return content format.
* @param {'ns' | 'us' | 'u' | 'ms' | 's'} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {WritePrecision} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: 'ns' | 'us' | 'u' | 'ms' | 's', options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise<Response> {
writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: WritePrecision, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise<Response> {
const localVarAxiosArgs = WriteApiAxiosParamCreator(configuration).writePost(org, bucket, body, contentEncoding, contentType, contentLength, accept, precision, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs = Object.assign(localVarAxiosArgs.options, {url: basePath + localVarAxiosArgs.url})
@ -16786,11 +16799,11 @@ export const WriteApiFactory = function (configuration?: Configuration, basePath
* @param {'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow'} [contentType] Content-Type is used to indicate the format of the data sent to the server.
* @param {number} [contentLength] Content-Length is an entity header is indicating the size of the entity-body, in bytes, sent to the database. If the length is greater than the database max body configuration option, a 413 response is sent.
* @param {'application/json'} [accept] specifies the return content format.
* @param {'ns' | 'us' | 'u' | 'ms' | 's'} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {WritePrecision} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: 'ns' | 'us' | 'u' | 'ms' | 's', options?: any) {
writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: WritePrecision, options?: any) {
return WriteApiFp(configuration).writePost(org, bucket, body, contentEncoding, contentType, contentLength, accept, precision, options)(axios, basePath);
},
};
@ -16813,12 +16826,12 @@ export class WriteApi extends BaseAPI {
* @param {'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow'} [contentType] Content-Type is used to indicate the format of the data sent to the server.
* @param {number} [contentLength] Content-Length is an entity header is indicating the size of the entity-body, in bytes, sent to the database. If the length is greater than the database max body configuration option, a 413 response is sent.
* @param {'application/json'} [accept] specifies the return content format.
* @param {'ns' | 'us' | 'u' | 'ms' | 's'} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {WritePrecision} [precision] specifies the precision for the unix timestamps within the body line-protocol
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof WriteApi
*/
public writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: 'ns' | 'us' | 'u' | 'ms' | 's', options?: any) {
public writePost(org: string, bucket: string, body: string, contentEncoding?: 'gzip' | 'identity', contentType?: 'text/plain' | 'text/plain; charset=utf-8' | 'application/vnd.influx.arrow', contentLength?: number, accept?: 'application/json', precision?: WritePrecision, options?: any) {
return WriteApiFp(this.configuration).writePost(org, bucket, body, contentEncoding, contentType, contentLength, accept, precision, options)(this.axios, this.basePath);
}

View File

@ -179,8 +179,20 @@
width: 100%;
max-width: 750px;
margin-top: 10px;
background-color: #202028;
background-color: $g6-smoke;
text-align: center;
> label {
font-size: small;
color: $g11-sidewalk;
margin: 10px;
}
&.dropdown {
justify-content: left;
align-items: left;
text-align: left;
}
}
.onboarding-step {

View File

@ -7,15 +7,17 @@ import {
import {writeLineProtocol} from 'src/onboarding/apis/index'
import {RemoteDataState} from 'src/types'
import {WritePrecision} from 'src/api'
export type Action =
| SetDataLoadersType
| AddTelegrafPlugin
| RemoveTelegrafPlugin
| SetActiveTelegrafPlugin
| SetLineProtocolText
| SetLineProtocolBody
| SetActiveLPTab
| SetLPStatus
| SetPrecision
interface SetDataLoadersType {
type: 'SET_DATA_LOADERS_TYPE'
@ -65,16 +67,16 @@ export const setActiveTelegrafPlugin = (
payload: {telegrafPlugin},
})
interface SetLineProtocolText {
type: 'SET_LINE_PROTOCOL_TEXT'
payload: {lineProtocolText: string}
interface SetLineProtocolBody {
type: 'SET_LINE_PROTOCOL_BODY'
payload: {lineProtocolBody: string}
}
export const setLineProtocolText = (
lineProtocolText: string
): SetLineProtocolText => ({
type: 'SET_LINE_PROTOCOL_TEXT',
payload: {lineProtocolText},
export const setLineProtocolBody = (
lineProtocolBody: string
): SetLineProtocolBody => ({
type: 'SET_LINE_PROTOCOL_BODY',
payload: {lineProtocolBody},
})
interface SetActiveLPTab {
@ -99,14 +101,25 @@ export const setLPStatus = (lpStatus: RemoteDataState): SetLPStatus => ({
payload: {lpStatus},
})
interface SetPrecision {
type: 'SET_PRECISION'
payload: {precision: WritePrecision}
}
export const setPrecision = (precision: WritePrecision): SetPrecision => ({
type: 'SET_PRECISION',
payload: {precision},
})
export const writeLineProtocolAction = (
org: string,
bucket: string,
body: string
body: string,
precision: WritePrecision
) => async dispatch => {
try {
dispatch(setLPStatus(RemoteDataState.Loading))
await writeLineProtocol(org, bucket, body)
await writeLineProtocol(org, bucket, body, precision)
dispatch(setLPStatus(RemoteDataState.Done))
} catch (error) {
dispatch(setLPStatus(RemoteDataState.Error))

View File

@ -4,7 +4,12 @@ import _ from 'lodash'
// Utils
import AJAX from 'src/utils/ajax'
import {telegrafsAPI, authorizationsAPI, writeAPI} from 'src/utils/api'
import {Telegraf, TelegrafRequest, TelegrafPluginInputCpu} from 'src/api'
import {
Telegraf,
TelegrafRequest,
TelegrafPluginInputCpu,
WritePrecision,
} from 'src/api'
import {getDeep} from 'src/utils/wrappers'
@ -135,8 +140,18 @@ export const getAuthorizationToken = async (
export const writeLineProtocol = async (
org: string,
bucket: string,
body: string
body: string,
precision: WritePrecision
): Promise<any> => {
const data = await writeAPI.writePost(org, bucket, body)
const data = await writeAPI.writePost(
org,
bucket,
body,
undefined,
undefined,
undefined,
undefined,
precision
)
return data
}

View File

@ -22,8 +22,6 @@ class ConfigureDataSourceSwitcher extends PureComponent<Props> {
public render() {
const {bucket, org} = this.props
switch (this.configurationStep) {
case DataLoaderType.Streaming:
return <div />
case DataLoaderType.LineProtocol:
return <LineProtocol bucket={bucket} org={org} />
case DataLoaderType.CSV:

View File

@ -8,11 +8,14 @@ import _ from 'lodash'
import LineProtocolTabs from 'src/onboarding/components/configureStep/lineProtocol/LineProtocolTabs'
import LoadingStatusIndicator from 'src/onboarding/components/configureStep/lineProtocol/LoadingStatusIndicator'
// Actions
import {setLPStatus as setLPStatusAction} from 'src/onboarding/actions/dataLoaders'
// Decorator
import {ErrorHandling} from 'src/shared/decorators/errors'
// Types
import {LineProtocolTab, LineProtocolStatus} from 'src/types/v2/dataLoaders'
import {LineProtocolTab} from 'src/types/v2/dataLoaders'
import {AppState} from 'src/types/v2/index'
import {RemoteDataState} from 'src/types'
@ -25,14 +28,14 @@ interface StateProps {
lpStatus: RemoteDataState
}
type Props = OwnProps & StateProps
interface DispatchProps {
setLPStatus: typeof setLPStatusAction
}
type Props = OwnProps & StateProps & DispatchProps
@ErrorHandling
export class LineProtocol extends PureComponent<Props> {
constructor(props) {
super(props)
this.state = {status: LineProtocolStatus.ImportData}
}
public render() {
return (
<>
@ -64,7 +67,17 @@ export class LineProtocol extends PureComponent<Props> {
/>
)
}
return <LoadingStatusIndicator status={lpStatus} />
return (
<LoadingStatusIndicator
status={lpStatus}
onClickRetry={this.handleRetry}
/>
)
}
private handleRetry = () => {
const {setLPStatus} = this.props
setLPStatus(RemoteDataState.NotStarted)
}
}
@ -76,4 +89,11 @@ const mstp = ({
return {lpStatus}
}
export default connect<StateProps, null, OwnProps>(mstp)(LineProtocol)
const mdtp: DispatchProps = {
setLPStatus: setLPStatusAction,
}
export default connect<StateProps, DispatchProps, OwnProps>(
mstp,
mdtp
)(LineProtocol)

View File

@ -3,24 +3,36 @@ import React, {PureComponent, ChangeEvent} from 'react'
import {connect} from 'react-redux'
// Components
import {Input, InputType, Radio, ButtonShape, Form} from 'src/clockface'
import {
Input,
InputType,
Radio,
ButtonShape,
Form,
Button,
ComponentSize,
ComponentColor,
} from 'src/clockface'
import DragAndDrop from 'src/shared/components/DragAndDrop'
import TextArea from 'src/clockface/components/inputs/TextArea'
import PrecisionDropdown from 'src/onboarding/components/configureStep/lineProtocol/PrecisionDropdown'
// Types
import {LineProtocolTab} from 'src/types/v2/dataLoaders'
// Actions
import {
setLineProtocolText,
setLineProtocolBody,
setActiveLPTab,
writeLineProtocolAction,
setPrecision,
} from 'src/onboarding/actions/dataLoaders'
import {AppState} from 'src/types/v2/index'
// Styles
import 'src/clockface/components/auto_input/AutoInput.scss'
import {WritePrecision} from 'src/api'
interface OwnProps {
tabs: LineProtocolTab[]
@ -31,22 +43,39 @@ interface OwnProps {
type Props = OwnProps & DispatchProps & StateProps
interface DispatchProps {
setLineProtocolText: typeof setLineProtocolText
setLineProtocolBody: typeof setLineProtocolBody
setActiveLPTab: typeof setActiveLPTab
writeLineProtocolAction: typeof writeLineProtocolAction
setPrecision: typeof setPrecision
}
interface StateProps {
lineProtocolText: string
lineProtocolBody: string
activeLPTab: LineProtocolTab
precision: WritePrecision
}
export class LineProtocolTabs extends PureComponent<Props> {
interface State {
urlInput: string
}
export class LineProtocolTabs extends PureComponent<Props, State> {
constructor(props: Props) {
super(props)
this.state = {
urlInput: '',
}
}
public render() {
const {setPrecision, precision} = this.props
return (
<>
{this.tabSelector}
<div className={'wizard-step--lp-body'}>{this.tabBody}</div>
<PrecisionDropdown setPrecision={setPrecision} precision={precision} />
<div className="wizard-button-bar">{this.submitButton}</div>
</>
)
}
@ -71,74 +100,98 @@ export class LineProtocolTabs extends PureComponent<Props> {
)
}
private get submitButton(): JSX.Element {
const {lineProtocolBody} = this.props
if (lineProtocolBody) {
return (
<Button
size={ComponentSize.Medium}
color={ComponentColor.Primary}
text={'submit line protocol'}
onClick={this.handleSubmitLineProtocol}
/>
)
}
return null
}
private handleTabClick = (tab: LineProtocolTab) => () => {
const {setActiveLPTab, setLineProtocolText} = this.props
setLineProtocolText('')
setActiveLPTab(tab)
const {setActiveLPTab, setLineProtocolBody, activeLPTab} = this.props
if (tab !== activeLPTab) {
setLineProtocolBody('')
setActiveLPTab(tab)
}
}
private get tabBody(): JSX.Element {
const {setLineProtocolText, lineProtocolText, activeLPTab} = this.props
if (activeLPTab === LineProtocolTab.UploadFile) {
return (
<DragAndDrop
submitText="Upload File"
handleSubmit={this.handleFileUpload}
/>
)
const {setLineProtocolBody, lineProtocolBody, activeLPTab} = this.props
const {urlInput} = this.state
switch (activeLPTab) {
case LineProtocolTab.UploadFile:
return (
<DragAndDrop
submitText="Upload File"
handleSubmit={setLineProtocolBody}
submitOnDrop={true}
submitOnUpload={true}
/>
)
case LineProtocolTab.EnterManually:
return (
<TextArea
value={lineProtocolBody}
placeholder="Write text here"
handleSubmitText={setLineProtocolBody}
/>
)
case LineProtocolTab.EnterURL:
return (
<Form className="onboarding--admin-user-form">
<Form.Element label="File URL:">
<Input
titleText="File URL:"
type={InputType.Text}
placeholder="http://..."
widthPixels={700}
value={urlInput}
onChange={this.handleURLChange}
autoFocus={true}
/>
</Form.Element>
</Form>
)
}
if (activeLPTab === LineProtocolTab.EnterManually) {
return (
<TextArea
value={lineProtocolText}
placeholder="Write text here"
handleSubmitText={setLineProtocolText}
/>
)
}
if (activeLPTab === LineProtocolTab.EnterURL) {
return (
<Form className="onboarding--admin-user-form">
<Form.Element label="File URL:">
<Input
titleText="File URL:"
type={InputType.Text}
placeholder="http://..."
widthPixels={700}
value={lineProtocolText}
onChange={this.handleChange}
autoFocus={true}
/>
</Form.Element>
</Form>
)
}
return
}
private handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const {setLineProtocolText} = this.props
setLineProtocolText(e.target.value)
}
private handleFileUpload = async (body: string): Promise<void> => {
const {bucket, org, writeLineProtocolAction} = this.props
writeLineProtocolAction(org, bucket, body)
private handleURLChange = (e: ChangeEvent<HTMLInputElement>) => {
this.setState({urlInput: e.target.value})
}
private handleSubmitLineProtocol = async (): Promise<void> => {
const {
bucket,
org,
writeLineProtocolAction,
lineProtocolBody,
precision,
} = this.props
writeLineProtocolAction(org, bucket, lineProtocolBody, precision)
}
}
const mstp = ({
onboarding: {
dataLoaders: {lineProtocolText, activeLPTab},
dataLoaders: {lineProtocolBody, activeLPTab, precision},
},
}: AppState) => {
return {lineProtocolText, activeLPTab}
return {lineProtocolBody, activeLPTab, precision}
}
const mdtp: DispatchProps = {
setLineProtocolText,
setLineProtocolBody,
setActiveLPTab,
writeLineProtocolAction,
setPrecision,
}
export default connect<StateProps, DispatchProps, OwnProps>(

View File

@ -14,6 +14,7 @@ import {RemoteDataState} from 'src/types'
interface Props {
status: RemoteDataState
onClickRetry: () => void
}
class LoadingStatusIndicator extends PureComponent<Props> {
@ -36,7 +37,7 @@ class LoadingStatusIndicator extends PureComponent<Props> {
}
private get retryButton(): JSX.Element {
const {status} = this.props
const {status, onClickRetry} = this.props
if (status === RemoteDataState.Error) {
return (
<Button
@ -44,6 +45,7 @@ class LoadingStatusIndicator extends PureComponent<Props> {
color={ComponentColor.Primary}
size={ComponentSize.Small}
customClass={'wizard-step--retry-button'}
onClick={onClickRetry}
/>
)
} else {

View File

@ -0,0 +1,54 @@
// Libraries
import React, {PureComponent} from 'react'
// Components
import {Dropdown} from 'src/clockface'
// Types
import {WritePrecision} from 'src/api'
import {Precision} from 'src/types/v2/dataLoaders'
interface Props {
setPrecision: (precision: WritePrecision) => void
precision: WritePrecision
}
const writePrecisions: WritePrecision[] = [
WritePrecision.Ms,
WritePrecision.S,
WritePrecision.U,
WritePrecision.Us,
WritePrecision.Ns,
]
const transformPrecision = {
[WritePrecision.Ns]: Precision.Nanoseconds,
[WritePrecision.Us]: Precision.Microseconds,
[WritePrecision.U]: Precision.U,
[WritePrecision.S]: Precision.Seconds,
[WritePrecision.Ms]: Precision.Milliseconds,
}
class PrecisionDropdown extends PureComponent<Props> {
public render() {
const {setPrecision, precision} = this.props
return (
<div className={'wizard-step--footer dropdown'}>
<label>Time Precision </label>
<Dropdown
selectedID={precision}
onChange={setPrecision}
widthPixels={200}
>
{writePrecisions.map(value => (
<Dropdown.Item key={value} value={value} id={value}>
{transformPrecision[value]}
</Dropdown.Item>
))}
</Dropdown>
</div>
)
}
}
export default PrecisionDropdown

View File

@ -12,6 +12,8 @@ exports[`LineProtocol rendering renders! 1`] = `
>
Need help writing InfluxDB Line Protocol? See Documentation
</h5>
<LoadingStatusIndicator />
<LoadingStatusIndicator
onClickRetry={[Function]}
/>
</Fragment>
`;

View File

@ -47,5 +47,9 @@ exports[`LineProtocolTabs rendering renders! 1`] = `
<div
className="wizard-step--lp-body"
/>
<PrecisionDropdown />
<div
className="wizard-button-bar"
/>
</Fragment>
`;

View File

@ -6,21 +6,24 @@ import {
LineProtocolTab,
} from 'src/types/v2/dataLoaders'
import {RemoteDataState} from 'src/types'
import {WritePrecision} from 'src/api'
export interface DataLoadersState {
telegrafPlugins: TelegrafPlugin[]
type: DataLoaderType
lineProtocolText: string
lineProtocolBody: string
activeLPTab: LineProtocolTab
lpStatus: RemoteDataState
precision: WritePrecision
}
export const INITIAL_STATE: DataLoadersState = {
telegrafPlugins: [],
type: DataLoaderType.Empty,
lineProtocolText: '',
lineProtocolBody: '',
activeLPTab: LineProtocolTab.UploadFile,
lpStatus: RemoteDataState.NotStarted,
precision: WritePrecision.Ms,
}
export default (state = INITIAL_STATE, action: Action): DataLoadersState => {
@ -55,10 +58,10 @@ export default (state = INITIAL_STATE, action: Action): DataLoadersState => {
return {...tp, active: false}
}),
}
case 'SET_LINE_PROTOCOL_TEXT':
case 'SET_LINE_PROTOCOL_BODY':
return {
...state,
lineProtocolText: action.payload.lineProtocolText,
lineProtocolBody: action.payload.lineProtocolBody,
}
case 'SET_ACTIVE_LP_TAB':
return {
@ -70,6 +73,11 @@ export default (state = INITIAL_STATE, action: Action): DataLoadersState => {
...state,
lpStatus: action.payload.lpStatus,
}
case 'SET_PRECISION':
return {
...state,
precision: action.payload.precision,
}
default:
return state
}

View File

@ -103,3 +103,11 @@ export enum LineProtocolStatus {
Success = 'success',
Error = 'error',
}
export enum Precision {
Milliseconds = 'Milliseconds',
Seconds = 'Seconds',
Microseconds = 'Microseconds',
U = 'U',
Nanoseconds = 'Nanoseconds',
}