Handle deletion of a tempVar used in nested tempVar
Catch error and send notification of errorpull/10616/head
parent
234023dd5e
commit
4156c42684
|
@ -1,6 +1,7 @@
|
|||
import {replace, RouterAction} from 'react-router-redux'
|
||||
import _ from 'lodash'
|
||||
import qs from 'qs'
|
||||
import {Dispatch} from 'redux'
|
||||
|
||||
import {
|
||||
getDashboards as getDashboardsAJAX,
|
||||
|
@ -38,6 +39,7 @@ import {
|
|||
notifyDashboardNotFound,
|
||||
notifyInvalidZoomedTimeRangeValueInURLQuery,
|
||||
notifyInvalidTimeRangeValueInURLQuery,
|
||||
notifyInvalidTempVarValueInMetaQuery,
|
||||
} from 'src/shared/copy/notifications'
|
||||
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
|
@ -396,7 +398,7 @@ const getDashboard = (state, dashboardId: number): Dashboard => {
|
|||
// Thunkers
|
||||
|
||||
export const getDashboardsAsync = () => async (
|
||||
dispatch
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<Dashboard[]> => {
|
||||
try {
|
||||
const {
|
||||
|
@ -442,7 +444,7 @@ const removeUnselectedTemplateValues = (dashboard: Dashboard): Template[] => {
|
|||
}
|
||||
|
||||
export const putDashboard = (dashboard: Dashboard) => async (
|
||||
dispatch
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
// save only selected template values to server
|
||||
|
@ -469,7 +471,7 @@ export const putDashboard = (dashboard: Dashboard) => async (
|
|||
}
|
||||
|
||||
export const putDashboardByID = (dashboardID: number) => async (
|
||||
dispatch,
|
||||
dispatch: Dispatch<Action>,
|
||||
getState
|
||||
): Promise<void> => {
|
||||
try {
|
||||
|
@ -483,7 +485,7 @@ export const putDashboardByID = (dashboardID: number) => async (
|
|||
}
|
||||
|
||||
export const updateDashboardCell = (dashboard: Dashboard, cell: Cell) => async (
|
||||
dispatch
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const {data} = await updateDashboardCellAJAX(cell)
|
||||
|
@ -495,7 +497,7 @@ export const updateDashboardCell = (dashboard: Dashboard, cell: Cell) => async (
|
|||
}
|
||||
|
||||
export const deleteDashboardAsync = (dashboard: Dashboard) => async (
|
||||
dispatch
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
dispatch(deleteDashboard(dashboard))
|
||||
try {
|
||||
|
@ -515,7 +517,7 @@ export const deleteDashboardAsync = (dashboard: Dashboard) => async (
|
|||
export const addDashboardCellAsync = (
|
||||
dashboard: Dashboard,
|
||||
cellType?: CellType
|
||||
) => async (dispatch): Promise<void> => {
|
||||
) => async (dispatch: Dispatch<Action>): Promise<void> => {
|
||||
try {
|
||||
const {data} = await addDashboardCellAJAX(
|
||||
dashboard,
|
||||
|
@ -532,7 +534,7 @@ export const addDashboardCellAsync = (
|
|||
export const cloneDashboardCellAsync = (
|
||||
dashboard: Dashboard,
|
||||
cell: Cell
|
||||
) => async (dispatch): Promise<void> => {
|
||||
) => async (dispatch: Dispatch<Action>): Promise<void> => {
|
||||
try {
|
||||
const clonedCell = getClonedDashboardCell(dashboard, cell)
|
||||
const {data} = await addDashboardCellAJAX(dashboard, clonedCell)
|
||||
|
@ -547,7 +549,7 @@ export const cloneDashboardCellAsync = (
|
|||
export const deleteDashboardCellAsync = (
|
||||
dashboard: Dashboard,
|
||||
cell: Cell
|
||||
) => async (dispatch): Promise<void> => {
|
||||
) => async (dispatch: Dispatch<Action>): Promise<void> => {
|
||||
try {
|
||||
await deleteDashboardCellAJAX(cell)
|
||||
dispatch(deleteDashboardCell(dashboard, cell))
|
||||
|
@ -559,7 +561,7 @@ export const deleteDashboardCellAsync = (
|
|||
}
|
||||
|
||||
export const importDashboardAsync = (dashboard: Dashboard) => async (
|
||||
dispatch
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
// save only selected template values to server
|
||||
|
@ -603,7 +605,7 @@ export const importDashboardAsync = (dashboard: Dashboard) => async (
|
|||
}
|
||||
|
||||
const updateTimeRangeFromQueryParams = (dashboardID: number) => (
|
||||
dispatch,
|
||||
dispatch: Dispatch<Action>,
|
||||
getState
|
||||
): void => {
|
||||
const {dashTimeV1} = getState()
|
||||
|
@ -660,6 +662,27 @@ const updateTimeRangeFromQueryParams = (dashboardID: number) => (
|
|||
dispatch(updateQueryParams(updatedQueryParams))
|
||||
}
|
||||
|
||||
const hydrateTemplates = (
|
||||
templates: Template[],
|
||||
nonNestedTemplates: Template[],
|
||||
proxyLink: string,
|
||||
dispatch: Dispatch<Action>
|
||||
) => {
|
||||
return templates.map(async t => {
|
||||
try {
|
||||
return await hydrateTemplate(proxyLink, t, nonNestedTemplates)
|
||||
} catch (error) {
|
||||
const errorMessage = getDeep(error, 'data.message', '')
|
||||
.replace(/.*(err):/g, '')
|
||||
.trim()
|
||||
dispatch(
|
||||
notify(notifyInvalidTempVarValueInMetaQuery(t.tempVar, errorMessage))
|
||||
)
|
||||
return t
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const getDashboardWithTemplatesAsync = (
|
||||
dashboardId: number,
|
||||
source: Source
|
||||
|
@ -679,17 +702,23 @@ export const getDashboardWithTemplatesAsync = (
|
|||
const templateSelections = templateSelectionsFromQueryParams()
|
||||
const proxyLink = source.links.proxy
|
||||
const nonNestedTemplates = await Promise.all(
|
||||
dashboard.templates
|
||||
.filter(t => !isTemplateNested(t))
|
||||
.map(t => hydrateTemplate(proxyLink, t, []))
|
||||
hydrateTemplates(
|
||||
dashboard.templates.filter(t => !isTemplateNested(t)),
|
||||
[],
|
||||
proxyLink,
|
||||
dispatch
|
||||
)
|
||||
)
|
||||
|
||||
applyLocalSelections(nonNestedTemplates, templateSelections)
|
||||
|
||||
const nestedTemplates = await Promise.all(
|
||||
dashboard.templates
|
||||
.filter(t => isTemplateNested(t))
|
||||
.map(t => hydrateTemplate(proxyLink, t, nonNestedTemplates))
|
||||
hydrateTemplates(
|
||||
dashboard.templates.filter(t => isTemplateNested(t)),
|
||||
nonNestedTemplates,
|
||||
proxyLink,
|
||||
dispatch
|
||||
)
|
||||
)
|
||||
|
||||
applyLocalSelections(nestedTemplates, templateSelections)
|
||||
|
@ -722,7 +751,7 @@ export const rehydrateNestedTemplatesAsync = (
|
|||
}
|
||||
|
||||
export const updateTemplateQueryParams = (dashboardId: number) => (
|
||||
dispatch,
|
||||
dispatch: Dispatch<Action>,
|
||||
getState
|
||||
): void => {
|
||||
const templates = getDashboard(getState(), dashboardId).templates
|
||||
|
|
|
@ -168,7 +168,20 @@ class DashboardPage extends Component<Props, State> {
|
|||
const prevPath = getDeep(prevProps.location, 'pathname', null)
|
||||
const thisPath = getDeep(this.props.location, 'pathname', null)
|
||||
|
||||
if (prevPath && thisPath && prevPath !== thisPath) {
|
||||
const templates = getDeep<TempVarsModels.Template[]>(
|
||||
this.props.dashboard,
|
||||
'templates',
|
||||
[]
|
||||
).map(t => t.tempVar)
|
||||
const prevTemplates = getDeep<TempVarsModels.Template[]>(
|
||||
prevProps.dashboard,
|
||||
'templates',
|
||||
[]
|
||||
).map(t => t.tempVar)
|
||||
const isTemplateDeleted: boolean =
|
||||
_.intersection(templates, prevTemplates).length !== prevTemplates.length
|
||||
|
||||
if ((prevPath && thisPath && prevPath !== thisPath) || isTemplateDeleted) {
|
||||
this.getDashboard()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -526,6 +526,16 @@ export const notifyBuilderDisabled = (): Notification => ({
|
|||
|
||||
// Template Variables & URL Queries
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyInvalidTempVarValueInMetaQuery = (
|
||||
tempVar: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
duration: 7500,
|
||||
message: `Invalid query supplied for template variable ${tempVar}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyInvalidTempVarValueInURLQuery = ({
|
||||
key,
|
||||
value,
|
||||
|
|
|
@ -16,28 +16,35 @@ export const hydrateTemplate = async (
|
|||
return template
|
||||
}
|
||||
|
||||
const query = templateReplace(makeQueryForTemplate(template.query), templates)
|
||||
const response = await proxy({source: proxyLink, query})
|
||||
const values = parseMetaQuery(query, response.data)
|
||||
const type = TEMPLATE_VARIABLE_TYPES[template.type]
|
||||
const selectedValue = getSelectedValue(template)
|
||||
const selectedLocalValue = getLocalSelectedValue(template)
|
||||
try {
|
||||
const query = templateReplace(
|
||||
makeQueryForTemplate(template.query),
|
||||
templates
|
||||
)
|
||||
const response = await proxy({source: proxyLink, query})
|
||||
const values = parseMetaQuery(query, response.data)
|
||||
const type = TEMPLATE_VARIABLE_TYPES[template.type]
|
||||
const selectedValue = getSelectedValue(template)
|
||||
const selectedLocalValue = getLocalSelectedValue(template)
|
||||
|
||||
const templateValues = values.map(value => {
|
||||
return {
|
||||
type,
|
||||
value,
|
||||
selected: value === selectedValue,
|
||||
localSelected: value === selectedLocalValue,
|
||||
const templateValues = values.map(value => {
|
||||
return {
|
||||
type,
|
||||
value,
|
||||
selected: value === selectedValue,
|
||||
localSelected: value === selectedLocalValue,
|
||||
}
|
||||
})
|
||||
|
||||
if (templateValues.length && !templateValues.find(v => v.selected)) {
|
||||
// Handle stale selected value
|
||||
templateValues[0].selected = true
|
||||
}
|
||||
})
|
||||
|
||||
if (templateValues.length && !templateValues.find(v => v.selected)) {
|
||||
// Handle stale selected value
|
||||
templateValues[0].selected = true
|
||||
return {...template, values: templateValues}
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
return {...template, values: templateValues}
|
||||
}
|
||||
|
||||
export const isTemplateNested = (template: Template): boolean => {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React, {Component} from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import TemplateControlDropdown from 'src/tempVars/components/TemplateControlDropdown'
|
||||
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
|
||||
import TemplateVariableEditor from 'src/tempVars/components/TemplateVariableEditor'
|
||||
|
@ -22,6 +24,7 @@ interface State {
|
|||
isAdding: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class TemplateControlBar extends Component<Props, State> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
|
Loading…
Reference in New Issue