Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"cy": "CYPRESS_dexUrl=https://$INGRESS_HOST:$PORT_HTTPS CYPRESS_baseUrl=http://localhost:9999 cypress open",
"cy:dev": "source ../monitor-ci/.env && CYPRESS_dexUrl=CLOUD CYPRESS_baseUrl=https://$INGRESS_HOST:$PORT_HTTPS cypress open --config testFiles='{cloud,shared}/**/*.*'",
"cy:dev-oss": "source ../monitor-ci/.env && CYPRESS_dexUrl=OSS CYPRESS_baseUrl=https://$INGRESS_HOST:$PORT_HTTPS cypress open --config testFiles='{oss,shared}/**/*.*'",
"generate": "export SHA=2da36d4beb7fc22dd8d037c3398c91c7ca2c346d && export REMOTE=https://raw.githubusercontent.com/influxdata/openapi/${SHA}/ && yarn generate-meta",
"generate": "export SHA=018d2381f78e52acbe1deaaff4c9512adf5e3703 && export REMOTE=https://raw.githubusercontent.com/influxdata/openapi/${SHA}/ && yarn generate-meta",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this SHA lives in a branch, maybe we should wait for this PR influxdata/openapi#248

"generate-local": "export REMOTE=../openapi/ && yarn generate-meta",
"generate-meta": "if [ -z \"${CLOUD_URL}\" ]; then yarn generate-meta-oss; else yarn generate-meta-cloud; fi",
"generate-meta-oss": "yarn oss-api && yarn notebooks && yarn unity && yarn annotations-oss && yarn pinned && yarn mapsd-oss && yarn cloudPriv",
Expand Down
9 changes: 9 additions & 0 deletions src/visualization/types/Graph/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {

// Annotations
import {addAnnotationLayer} from 'src/visualization/utils/annotationUtils'
import {getColorMappingObjects} from 'src/visualization/utils/colorMappingUtils'

interface Props extends VisualizationProps {
properties: XYViewProperties
Expand Down Expand Up @@ -179,6 +180,13 @@ const XYPlot: FC<Props> = ({
return <EmptyGraphMessage message={INVALID_DATA_COPY} />
}

const [, fillColumnMap] = createGroupIDColumn(result.table, groupKey)

const {colorMappingForGiraffe} = getColorMappingObjects(
fillColumnMap,
properties
)

const config: Config = {
...currentTheme,
table: result.table,
Expand Down Expand Up @@ -210,6 +218,7 @@ const XYPlot: FC<Props> = ({
interpolation,
position: properties.position,
colors: colorHexes,
colorMapping: colorMappingForGiraffe,
shadeBelow: !!properties.shadeBelow,
shadeBelowOpacity: 0.08,
hoverDimension: properties.hoverDimension,
Expand Down
144 changes: 144 additions & 0 deletions src/visualization/utils/colorMappingUtils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// tests will go here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✂️


import {getColorMappingObjects} from './colorMappingUtils'
import {XYViewProperties} from '../../client'

const MOCK_START = 1639775162126
const MOCK_STOP = 1639778762126
const dataFromIDPE_noColorMapping = {
columnGroup: {
mappings: [
{
_start: `${MOCK_START}`,
_stop: `${MOCK_STOP}`,
_field: 'co',
_measurement: 'airSensors',
sensor_id: 'TLM0100',
result: 'mean',
},
{
_start: `${MOCK_START}`,
_stop: `${MOCK_STOP}`,
_field: 'co',
_measurement: 'airSensors',
sensor_id: 'TLM0101',
result: 'mean',
},
{
_start: `${MOCK_START}`,
_stop: `${MOCK_STOP}`,
_field: 'co',
_measurement: 'airSensors',
sensor_id: 'TLM0102',
result: 'mean',
},
],
columnKeys: [
'_start',
'_stop',
'_field',
'_measurement',
'sensor_id',
'result',
],
},
properties: {
// no colorMapping present
colors: [
{
id: '2f2d8b62-5e53-46b2-bde9-a291bcc5f9e7',
type: 'scale',
hex: '#31C0F6',
name: 'Nineteen Eighty Four',
value: 0,
},
{
id: '4b0d1e17-2177-40cf-b524-980fe80f6ca8',
type: 'scale',
hex: '#A500A5',
name: 'Nineteen Eighty Four',
value: 0,
},
{
id: 'd90d4be9-14f8-48da-a309-8d2cb50f6961',
type: 'scale',
hex: '#FF7E27',
name: 'Nineteen Eighty Four',
value: 0,
},
],
},
}

const expectedData = {
mappingForGiraffe: {
mappings: [
{
_start: `${MOCK_START}`,
_stop: `${MOCK_STOP}`,
_field: 'co',
_measurement: 'airSensors',
sensor_id: 'TLM0100',
result: 'mean',
color: '#31C0F6',
},
{
_start: `${MOCK_START}`,
_stop: `${MOCK_STOP}`,
_field: 'co',
_measurement: 'airSensors',
sensor_id: 'TLM0101',
result: 'mean',
color: '#A500A5',
},
{
_start: `${MOCK_START}`,
_stop: `${MOCK_STOP}`,
_field: 'co',
_measurement: 'airSensors',
sensor_id: 'TLM0102',
result: 'mean',
color: '#FF7E27',
},
],
columnKeys: [
'_start',
'_stop',
'_field',
'_measurement',
'sensor_id',
'result',
],
seriesToColorIndexMap: {
'co-airSensors-TLM0100-mean-': 0,
'co-airSensors-TLM0101-mean-': 1,
'co-airSensors-TLM0102-mean-': 2,
},
},
mappingForIDPE: {
colorMapping: {
'co-airSensors-TLM0100-mean-': 0,
'co-airSensors-TLM0101-mean-': 1,
'co-airSensors-TLM0102-mean-': 2,
},
},
}

describe('color mapping utils', function() {
it('should generate a color mapping when view properties from the IDPE do not have colorMapping', function() {
const {
colorMappingForGiraffe,
colorMappingForIDPE,
needsToSaveToIDPE,
} = getColorMappingObjects(
dataFromIDPE_noColorMapping.columnGroup,
dataFromIDPE_noColorMapping.properties as XYViewProperties
)

expect(colorMappingForGiraffe).toStrictEqual(expectedData.mappingForGiraffe)
expect(needsToSaveToIDPE).toBe(true)
expect(colorMappingForIDPE).toStrictEqual(
expectedData.mappingForIDPE.colorMapping
)
})
})
130 changes: 130 additions & 0 deletions src/visualization/utils/colorMappingUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import {XYViewProperties} from 'src/types'

/**
* Evaluates deeper equality for two map objects based on their key:value pair
* @param map1
* @param map2
*/
const areMappingsSame = (map1, map2) => {
if (!map1 || !map2) {
return false
}

// Create arrays of property names
const aProps = Object.getOwnPropertyNames(map1)
const bProps = Object.getOwnPropertyNames(map2)

// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
return false
}

for (let i = 0; i < aProps.length; i++) {
const propName = aProps[i]

// If values of same property are not equal,
// objects are not equivalent
if (map1[propName] !== map2[propName]) {
return false
}
}

return true
}

/**
* Returns the colorMapping objects for UI, based on the state of the current view it will return the existing or generate a new one and request trigger saving to IDPE
* @param columnGroupMap
* @param properties
* @returns an object shaped : {colorMappingForIDPE?, colorMappingForGiraffe?, needsToSaveToIDPE}
*/

export const getColorMappingObjects = (
columnGroupMap,
properties: XYViewProperties
) => {
const seriesToColorIndexMap = generateSeriesToColorIndexMap(
columnGroupMap,
properties
)
let needsToSaveToIDPE = false

// if the mappings from the IDPE and the *required* one's for the current view are the same, we don't need to generate new mappings
if (areMappingsSame(properties.colorMapping, seriesToColorIndexMap)) {
const columnKeys = columnGroupMap.columnKeys
const mappings = {...columnGroupMap}

mappings.mappings.forEach(graphLine => {
const seriesID = getSeriesId(graphLine, columnKeys)

const colors = properties.colors

// this is needed for giraffe
graphLine.color = colors[properties.colorMapping[seriesID]].hex
})

needsToSaveToIDPE = false

return {
colorMappingForGiraffe: {columnKeys, ...mappings},
needsToSaveToIDPE,
}
} else {
const columnKeys = columnGroupMap.columnKeys
const mappings = {...columnGroupMap}

mappings.mappings.forEach(graphLine => {
const seriesID = getSeriesId(graphLine, columnKeys)

const colors = properties.colors

// this is needed for giraffe
graphLine.color = colors[seriesToColorIndexMap[seriesID]].hex
})

const newColorMappingForGiraffe = {
...mappings,
seriesToColorIndexMap,
}
needsToSaveToIDPE = true

return {
colorMappingForIDPE: seriesToColorIndexMap,
colorMappingForGiraffe: newColorMappingForGiraffe,
needsToSaveToIDPE,
}
}
}

const getSeriesId = (graphLine, columnKeys) => {
let id = ''
for (const key of columnKeys) {
// ignore the '_start' and '_stop' columns when generating the ID.
if (key !== '_start' && key !== '_stop') {
id += graphLine[key] + '-'
}
}
return id
}

/**
* This function generates a map that maps the series ID to the color Index.
* @param columnGroupMap - generated using the createGroupIDColumn function
* @param properties - XYViewProperties
* @returns - a map that contains the series ID and it's color index (value bounded by the properties.colors array)
*/

export const generateSeriesToColorIndexMap = (
columnGroupMap,
properties: XYViewProperties
) => {
const seriesToColorIndexMap = {}
const cgMap = {...columnGroupMap}
cgMap.mappings.forEach((graphLine, colorIndex) => {
const id = getSeriesId(graphLine, columnGroupMap.columnKeys)
seriesToColorIndexMap[id] = colorIndex % properties.colors.length
})

return {...seriesToColorIndexMap}
}