fix(ui/mapVarsToCSV): double quote map template values (#5118)

pull/5128/head
Delmer 2019-03-18 15:50:31 -04:00 committed by GitHub
parent 6636a61a1f
commit d9c46c6d28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 282 additions and 39 deletions

View File

@ -3,6 +3,7 @@
1. [#5110](https://github.com/influxdata/chronograf/pull/5110): Fix the input for line controls in visualization options.
1. [#5111](https://github.com/influxdata/chronograf/pull/5111): Stop scrollbars from covering text in flux editor
1. [#5114](https://github.com/influxdata/chronograf/pull/5114): Insert flux function near cursor in flux editor
1. [#5118](https://github.com/influxdata/chronograf/pull/5118): Fix double quoting of map template values
## v1.7.8 [2019-02-08]
### Bug Fixes

View File

@ -1,10 +1,8 @@
import React, {PureComponent, ChangeEvent} from 'react'
import {getDeep} from 'src/utils/wrappers'
import Papa from 'papaparse'
import _ from 'lodash'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {csvToMap, mapToCSV} from 'src/tempVars/utils'
import TemplatePreviewList from 'src/tempVars/components/TemplatePreviewList'
import DragAndDrop from 'src/shared/components/DragAndDrop'
import {
@ -12,8 +10,7 @@ import {
notifyInvalidMapType,
} from 'src/shared/copy/notifications'
import {TemplateBuilderProps, TemplateValueType} from 'src/types'
import {trimAndRemoveQuotes} from 'src/tempVars/utils'
import {TemplateBuilderProps} from 'src/types'
interface State {
templateValuesString: string
@ -23,11 +20,7 @@ interface State {
class MapTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
public constructor(props: TemplateBuilderProps) {
super(props)
const templateValues = props.template.values.map(v => v.value)
const templateKeys = props.template.values.map(v => v.key)
const templateValuesString = templateKeys
.map((v, i) => `${v}, ${templateValues[i]}`)
.join('\n')
const templateValuesString = mapToCSV(props.template.values)
this.state = {
templateValuesString,
@ -120,38 +113,13 @@ class MapTemplateBuilder extends PureComponent<TemplateBuilderProps, State> {
private constructValuesFromString(templateValuesString: string) {
const {notify} = this.props
const trimmed = _.trimEnd(templateValuesString, '\n')
const parsedTVS = Papa.parse(trimmed)
const templateValuesData = getDeep<string[][]>(parsedTVS, 'data', [[]])
if (templateValuesData.length === 0) {
return
const {errors, values} = csvToMap(templateValuesString)
if (errors.length > 0) {
notify(notifyInvalidMapType())
}
let arrayOfKeys = []
let values = []
_.forEach(templateValuesData, arr => {
if (arr.length === 2 || (arr.length === 3 && arr[2] === '')) {
const key = trimAndRemoveQuotes(arr[0])
const value = trimAndRemoveQuotes(arr[1])
if (!arrayOfKeys.includes(key) && key !== '') {
values = [
...values,
{
type: TemplateValueType.Map,
value,
key,
selected: false,
localSelected: false,
},
]
arrayOfKeys = [...arrayOfKeys, key]
}
} else {
notify(notifyInvalidMapType())
}
})
return values
}
}

View File

@ -1,3 +1,6 @@
import _ from 'lodash'
import Papa from 'papaparse'
import {TEMPLATE_VARIABLE_TYPES} from 'src/tempVars/constants'
import {
Template,
@ -163,3 +166,49 @@ export const getLocalSelectedValue = (template: Template): string | null => {
return null
}
interface MapResult {
values: TemplateValue[]
errors: string[]
}
export const csvToMap = (csv: string): MapResult => {
let errors = []
const trimmed = _.trimEnd(csv, '\n')
const parsedTVS = Papa.parse(trimmed)
const templateValuesData: string[][] = _.get(parsedTVS, 'data', [[]])
if (templateValuesData.length === 0) {
return
}
let arrayOfKeys = []
let values = []
for (const arr of templateValuesData) {
if (arr.length === 2 || (arr.length === 3 && arr[2] === '')) {
const key = trimAndRemoveQuotes(arr[0])
const value = trimAndRemoveQuotes(arr[1])
if (!arrayOfKeys.includes(key) && key !== '') {
values = [
...values,
{
type: TemplateValueType.Map,
value,
key,
selected: false,
localSelected: false,
},
]
arrayOfKeys = [...arrayOfKeys, key]
}
} else {
errors = [...errors, arr[0]]
}
}
return {values, errors}
}
export const mapToCSV = (values: TemplateValue[]): string =>
values.map(v => `${v.key},"${v.value}"`).join('\n')

View File

@ -0,0 +1,225 @@
import {csvToMap, mapToCSV} from 'src/tempVars/utils'
import {TemplateValueType} from 'src/types'
describe('MapVars', () => {
const mapDefaults = {
type: TemplateValueType.Map,
value: '',
key: '',
selected: false,
localSelected: false,
}
describe('csvToMap', () => {
it('can parse key values', () => {
const csv = 'a,1\nb,2\nc,3\n'
const {values: actual} = csvToMap(csv)
expect(actual).toEqual([
{
...mapDefaults,
key: 'a',
value: '1',
},
{
...mapDefaults,
key: 'b',
value: '2',
},
{
...mapDefaults,
key: 'c',
value: '3',
},
])
})
it('records invalid keys', () => {
const csv = 'a,1,2\nb,2\nc,3\n'
const {values: actual, errors} = csvToMap(csv)
expect(actual).toEqual([
{
...mapDefaults,
key: 'b',
value: '2',
},
{
...mapDefaults,
key: 'c',
value: '3',
},
])
expect(errors).toEqual(['a'])
})
it('can parse single quoted values', () => {
const csv = `a,'1'\nb,'2'\nc,'3'\n`
const {values: actual} = csvToMap(csv)
expect(actual).toEqual([
{
...mapDefaults,
key: 'a',
value: `'1'`,
},
{
...mapDefaults,
key: 'b',
value: `'2'`,
},
{
...mapDefaults,
key: 'c',
value: `'3'`,
},
])
})
it('can parse single quoted values with commas and spaces', () => {
const csv = `a,"'1, 2'"\nb,"'2, 3'"\nc,"'3, 4'"\n`
const {values: actual} = csvToMap(csv)
expect(actual).toEqual([
{
...mapDefaults,
key: 'a',
value: `'1, 2'`,
},
{
...mapDefaults,
key: 'b',
value: `'2, 3'`,
},
{
...mapDefaults,
key: 'c',
value: `'3, 4'`,
},
])
})
it('can parse double quoted values', () => {
const csv = `a,"1"\nb,"2"\nc,"3"\n`
const {values: actual} = csvToMap(csv)
expect(actual).toEqual([
{
...mapDefaults,
key: 'a',
value: '1',
},
{
...mapDefaults,
key: 'b',
value: '2',
},
{
...mapDefaults,
key: 'c',
value: '3',
},
])
})
it('can parse double quoted values with commas', () => {
const csv = `a,"1, 2"\nb,"2, 3"\nc,"3, 4"\n`
const {values: actual} = csvToMap(csv)
expect(actual).toEqual([
{
...mapDefaults,
key: 'a',
value: '1, 2',
},
{
...mapDefaults,
key: 'b',
value: '2, 3',
},
{
...mapDefaults,
key: 'c',
value: '3, 4',
},
])
})
})
describe('mapToCSV', () => {
it('can create a CSV', () => {
const actual = mapToCSV([
{
...mapDefaults,
key: 'a',
value: '1',
},
{
...mapDefaults,
key: 'b',
value: '2',
},
{
...mapDefaults,
key: 'c',
value: '3',
},
])
const expected = 'a,"1"\nb,"2"\nc,"3"'
expect(actual).toEqual(expected)
})
})
it('can double quote single quoted values', () => {
const actual = mapToCSV([
{
...mapDefaults,
key: 'a',
value: `'1, 2'`,
},
{
...mapDefaults,
key: 'b',
value: `'2, 3'`,
},
{
...mapDefaults,
key: 'c',
value: `'3, 4'`,
},
])
const expected = `a,"'1, 2'"\nb,"'2, 3'"\nc,"'3, 4'"`
expect(actual).toEqual(expected)
})
it('can double quote keys with CSV values', () => {
const actual = mapToCSV([
{
...mapDefaults,
key: 'a',
value: '1, 2',
},
{
...mapDefaults,
key: 'b',
value: '2, 3',
},
{
...mapDefaults,
key: 'c',
value: '3, 4',
},
])
const expected = `a,"1, 2"\nb,"2, 3"\nc,"3, 4"`
expect(actual).toEqual(expected)
})
})