fix(ui/mapVarsToCSV): double quote map template values (#5118)
parent
6636a61a1f
commit
d9c46c6d28
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue