Synchronize temp vars with URL query params

Refactor action creator & reducer for updating tempvar overrides.

Authored-by: Jared Scheib <jared.scheib@gmail.com>
pull/3556/head
Jared Scheib 2018-05-25 17:12:42 -07:00
parent 187752d49d
commit fb63b6f63f
5 changed files with 127 additions and 50 deletions

View File

@ -1,3 +1,6 @@
import {push} from 'react-router-redux'
import queryString from 'query-string'
import {
getDashboards as getDashboardsAJAX,
updateDashboard as updateDashboardAJAX,
@ -174,14 +177,14 @@ export const templateVariablesSelectedByName = (dashboardID, query) => ({
},
})
export const editTemplateVariableOverrides = (
export const updateTemplateVariableOverride = (
dashboardID,
tempVarOverrides
updatedTempVarOverride
) => ({
type: 'EDIT_TEMPLATE_VARIABLE_OVERRIDES',
type: 'UPDATE_TEMPLATE_VARIABLE_OVERRIDE',
payload: {
dashboardID,
tempVarOverrides,
updatedTempVarOverride,
},
})
@ -362,10 +365,26 @@ export const updateTempVarValues = (source, dashboard) => async dispatch => {
const {type, query, id} = tempsWithQueries[i]
const parsed = parsers[type](data, query.tagKey || query.measurement)
const vals = parsed[type]
dispatch(editTemplateVariableValues(dashboard.id, id, vals))
dispatch(editTemplateVariableValues(+dashboard.id, id, vals))
})
} catch (error) {
console.error(error)
dispatch(errorThrown(error))
}
}
export const updateURLQueryValue = (
location,
updatedQueryParam
) => dispatch => {
const updatedLocationQuery = {...location.query, ...updatedQueryParam}
const updatedSearchString = queryString.stringify(updatedLocationQuery)
const updatedSearch = {search: updatedSearchString}
const updatedLocation = {
...location,
query: updatedLocationQuery,
...updatedSearch,
}
dispatch(push(updatedLocation))
}

View File

@ -29,6 +29,11 @@ import {
} from 'src/dashboards/actions/cellEditorOverlay'
import {showOverlay} from 'src/shared/actions/overlayTechnology'
import {
applyDashboardTempVarOverrides,
stripTempVar,
} from 'src/dashboards/utils/templateVariableQueryGenerator'
import {dismissEditingAnnotation} from 'src/shared/actions/annotations'
import {
@ -255,15 +260,31 @@ class DashboardPage extends Component {
dashboardActions.deleteDashboardCellAsync(dashboard, cell)
}
handleSelectTemplate = templateID => values => {
handleSelectTemplate = templateID => value => {
const {
dashboardActions,
dashboard,
params: {dashboardID},
location,
} = this.props
dashboardActions.templateVariableSelected(dashboard.id, templateID, [
values,
])
// TODO: block viewer from doing this
const currentTempVar = dashboard.templates.find(
tempVar => tempVar.id === templateID
)
const strippedTempVar = stripTempVar(currentTempVar.tempVar)
const isTempVarInURLQuery = !!location.query[strippedTempVar]
if (isTempVarInURLQuery) {
const updatedQueryParam = {
[strippedTempVar]: value.value,
}
dashboardActions.updateURLQueryValue(location, updatedQueryParam)
dashboardActions.updateTemplateVariableOverride(
dashboardID,
updatedQueryParam
)
}
dashboardActions.templateVariableSelected(dashboard.id, templateID, [value])
dashboardActions.putDashboardByID(dashboardID)
}
@ -545,6 +566,7 @@ DashboardPage.propTypes = {
gaugeColors: colorsNumberSchema.isRequired,
lineColors: colorsStringSchema.isRequired,
handleShowOverlay: func.isRequired,
tempVarOverrides: shape({}),
}
const mapStateToProps = (state, {params: {dashboardID}}) => {
@ -553,7 +575,7 @@ const mapStateToProps = (state, {params: {dashboardID}}) => {
ephemeral: {inPresentationMode},
persisted: {autoRefresh, showTemplateControlBar},
},
dashboardUI: {dashboards, cellQueryStatus},
dashboardUI: {dashboards, cellQueryStatus, tempVarOverrides},
sources,
dashTimeV1,
auth: {me, isUsingAuth},
@ -573,10 +595,17 @@ const mapStateToProps = (state, {params: {dashboardID}}) => {
r => r.dashboardID === idNormalizer(TYPE_ID, dashboardID)
) || defaultTimeRange
const dashboard = dashboards.find(
let dashboard = dashboards.find(
d => d.id === idNormalizer(TYPE_ID, dashboardID)
)
if (dashboard) {
dashboard = applyDashboardTempVarOverrides(
dashboard,
tempVarOverrides[dashboard.id]
)
}
const selectedCell = cell
return {

View File

@ -2,6 +2,8 @@ import _ from 'lodash'
import {timeRanges} from 'shared/data/timeRanges'
import {NULL_HOVER_TIME} from 'src/shared/constants/tableGraph'
import {applyDashboardTempVarOverrides} from 'src/dashboards/utils/templateVariableQueryGenerator'
const {lower, upper} = timeRanges.find(tr => tr.lower === 'now() - 1h')
const initialState = {
@ -235,54 +237,28 @@ export default function ui(state = initialState, action) {
case 'TEMPLATE_VARIABLES_SELECTED_BY_NAME': {
const {dashboardID, query} = action.payload
const selecteds = Object.keys(query).map(k => ({
tempVar: `:${k}:`,
selectedValue: query[k],
}))
const makeNewValue = (value, selected) => ({...value, selected})
const makeNewValues = template => ({
...template,
values: template.values.map(
value =>
selecteds.find(({selectedValue}) => selectedValue === value.value)
? makeNewValue(value, true)
: makeNewValue(value, false)
),
})
const makeNewTemplates = templates =>
templates.map(
template =>
selecteds.find(({tempVar}) => tempVar === template.tempVar)
? makeNewValues(template)
: template
)
const makeNewDashboard = dashboard => ({
...dashboard,
templates: makeNewTemplates(dashboard.templates),
})
const newDashboards = state.dashboards.map(
oldDashboard =>
oldDashboard.id === dashboardID
? makeNewDashboard(oldDashboard)
? applyDashboardTempVarOverrides(oldDashboard, query)
: oldDashboard
)
return {...state, dashboards: newDashboards}
}
case 'EDIT_TEMPLATE_VARIABLE_OVERRIDES': {
const {dashboardID, tempVarOverrides} = action.payload
case 'UPDATE_TEMPLATE_VARIABLE_OVERRIDE': {
const {dashboardID, updatedTempVarOverride} = action.payload
const updatedTempVarOverrides = {
...state.tempVarOverrides[dashboardID],
...updatedTempVarOverride,
}
return {
...state,
tempVarOverrides: {
...state.tempVarOverrides,
[dashboardID]: tempVarOverrides,
[dashboardID]: updatedTempVarOverrides,
},
}
}

View File

@ -59,4 +59,53 @@ export const makeQueryForTemplate = ({influxql, db, measurement, tagKey}) =>
.replace(':measurement:', `"${measurement}"`)
.replace(':tagKey:', `"${tagKey}"`)
export const stripTempVar = tempVarName =>
tempVarName.substr(1, tempVarName.length - 2)
const reconcileTempVarsWithOverrides = (currentTempVars, tempVarOverrides) => {
if (!tempVarOverrides) {
return currentTempVars
}
const reconciledTempVars = currentTempVars.map(tempVar => {
const {tempVar: name, values} = tempVar
const strippedTempVar = stripTempVar(name)
const overrideValue = tempVarOverrides[strippedTempVar]
if (overrideValue) {
const isValidTempVarOverride = !!values.find(
({value}) => value === overrideValue
)
if (isValidTempVarOverride) {
const overriddenValues = values.map(tempVarValue => {
const {value} = tempVarValue
if (value === overrideValue) {
return {...tempVarValue, selected: true}
}
return {...tempVarValue, selected: false}
})
return {...tempVar, values: overriddenValues}
}
// TODO: generate error notification ?
return tempVar
}
return tempVar
})
return reconciledTempVars
}
export const applyDashboardTempVarOverrides = (
dashboard,
tempVarOverrides
) => ({
...dashboard,
templates: reconcileTempVarsWithOverrides(
dashboard.templates,
tempVarOverrides
),
})
export default generateTemplateVariableQuery

View File

@ -1,20 +1,21 @@
import _ from 'lodash'
// Middleware generally used for actions needing parsed queryStrings
import queryString from 'query-string'
import {enablePresentationMode} from 'src/shared/actions/app'
import {
templateVariablesSelectedByName,
editTemplateVariableOverrides,
updateTemplateVariableOverride,
} from 'src/dashboards/actions'
export const queryStringConfig = () => {
let prevPath
return next => action => {
next(action)
const qs = queryString.parse(window.location.search)
const queries = queryString.parse(window.location.search)
// Presentation Mode
if (qs.present === 'true') {
if (queries.present === 'true') {
next(enablePresentationMode())
}
@ -24,8 +25,11 @@ export const queryStringConfig = () => {
const currentPath = window.location.pathname
const dashboardID = currentPath.match(dashboardRegex)[2]
if (currentPath !== prevPath) {
next(templateVariablesSelectedByName(+dashboardID, qs))
next(editTemplateVariableOverrides(dashboardID, qs))
next(templateVariablesSelectedByName(+dashboardID, queries))
_.each(queries, (v, k) => {
const query = {[k]: v}
next(updateTemplateVariableOverride(+dashboardID, query))
})
}
prevPath = currentPath