chore(ui): refactored dashboards client API to oats generated types and API (#16438)

chore(ui): refactored dashboards to use oats generated api rather than client
pull/16520/head
Ariel Salem 2020-01-13 08:26:58 -08:00 committed by GitHub
parent 3b62340b31
commit 03335cceb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 321 additions and 155 deletions

View File

@ -456,11 +456,11 @@ describe('DataExplorer', () => {
.click()
.focused()
.type(
`from(bucket: "defbuck")
`from(bucket: "defbuck")
|> range(start: -10s)
|> filter(fn: (r) => r._measurement == "no exist")`,
{force: true, delay: TYPE_DELAY}
)
{force: true, delay: TYPE_DELAY}
)
cy.getByTestID('time-machine-submit-button').click()
})
@ -475,11 +475,11 @@ describe('DataExplorer', () => {
.click()
.focused()
.type(
`from(bucket: "defbuck")
`from(bucket: "defbuck")
|> range(start: -15m, stop: now())
|> filter(fn: (r) => r._measurement == `,
{force: true, delay: TYPE_DELAY}
)
{force: true, delay: TYPE_DELAY}
)
})
cy.getByTestID('toolbar-tab').click()

View File

@ -319,9 +319,9 @@ http.post(
cy.get<Bucket>('@bucket').then(bucket => {
cy.getByTestID('flux-editor').within(() => {
cy.get('.react-monaco-editor-container')
.click()
.focused()
.type(flux(bucket), {force: true, delay: 2})
.click()
.focused()
.type(flux(bucket), {force: true, delay: 2})
})
})
cy.getByTestID('task-save-btn').click()

View File

@ -15,7 +15,16 @@ import {
getView as getViewAJAX,
updateView as updateViewAJAX,
} from 'src/dashboards/apis'
import {getVariables as apiGetVariables} from 'src/client'
import {
getVariables as apiGetVariables,
getDashboard as apiGetDashboard,
postDashboard as apiPostDashboard,
postDashboardsCell as apiPostDashboardsCell,
postDashboardsLabel as apiPostDashboardsLabel,
deleteDashboardsLabel as apiDeleteDashboardsLabel,
patchDashboardsCellsView as apiPatchDashboardsCellsView,
getDashboardsCellsView as apiGetDashboardsCellsView,
} from 'src/client'
import {createDashboardFromTemplate as createDashboardFromTemplateAJAX} from 'src/templates/api'
// Actions
@ -50,20 +59,18 @@ import {
getClonedDashboardCell,
} from 'src/dashboards/utils/cellGetters'
import {dashboardToTemplate} from 'src/shared/utils/resourceToTemplate'
import {client} from 'src/utils/api'
import {exportVariables} from 'src/variables/utils/exportVariables'
import {getSaveableView} from 'src/timeMachine/selectors'
import {incrementCloneName} from 'src/utils/naming'
import {isLimitError} from 'src/cloud/utils/limits'
import {getOrg} from 'src/organizations/selectors'
import {addLabelDefaults} from 'src/labels/utils'
// Constants
import * as copy from 'src/shared/copy/notifications'
import {DEFAULT_DASHBOARD_NAME} from 'src/dashboards/constants/index'
// Types
import {RemoteDataState} from 'src/types'
import {CreateCell} from '@influxdata/influx'
import {
Dashboard,
NewView,
@ -72,7 +79,36 @@ import {
View,
DashboardTemplate,
Label,
RemoteDataState,
NewCell,
} from 'src/types'
import {
Dashboard as IDashboard,
Cell as ICell,
DashboardWithViewProperties,
} from 'src/client'
export const addDashboardIDToCells = (
cells: ICell[],
dashboardID: string
): Cell[] => {
return cells.map(c => {
return {...c, dashboardID}
})
}
export const addDashboardDefaults = (
dashboard: IDashboard | DashboardWithViewProperties
): Dashboard => {
return {
...dashboard,
cells: addDashboardIDToCells(dashboard.cells, dashboard.id) || [],
id: dashboard.id || '',
labels: (dashboard.labels || []).map(addLabelDefaults),
name: dashboard.name || '',
orgID: dashboard.orgID || '',
}
}
export enum ActionTypes {
SetDashboards = 'SET_DASHBOARDS',
@ -81,8 +117,8 @@ export enum ActionTypes {
DeleteDashboardFailed = 'DELETE_DASHBOARD_FAILED',
EditDashboard = 'EDIT_DASHBOARD',
RemoveCell = 'REMOVE_CELL',
AddDashboardLabels = 'ADD_DASHBOARD_LABELS',
RemoveDashboardLabels = 'REMOVE_DASHBOARD_LABELS',
AddDashboardLabel = 'ADD_DASHBOARD_LABEL',
RemoveDashboardLabel = 'REMOVE_DASHBOARD_LABEL',
}
export type Action =
@ -94,8 +130,8 @@ export type Action =
| SetViewAction
| DeleteTimeRangeAction
| DeleteDashboardFailedAction
| AddDashboardLabelsAction
| RemoveDashboardLabelsAction
| AddDashboardLabelAction
| RemoveDashboardLabelAction
interface RemoveCellAction {
type: ActionTypes.RemoveCell
@ -141,19 +177,19 @@ interface SetDashboardAction {
}
}
interface AddDashboardLabelsAction {
type: ActionTypes.AddDashboardLabels
interface AddDashboardLabelAction {
type: ActionTypes.AddDashboardLabel
payload: {
dashboardID: string
labels: Label[]
label: Label
}
}
interface RemoveDashboardLabelsAction {
type: ActionTypes.RemoveDashboardLabels
interface RemoveDashboardLabelAction {
type: ActionTypes.RemoveDashboardLabel
payload: {
dashboardID: string
labels: Label[]
label: Label
}
}
@ -217,20 +253,20 @@ export const removeCell = (
payload: {dashboard, cell},
})
export const addDashboardLabels = (
export const addDashboardLabel = (
dashboardID: string,
labels: Label[]
): AddDashboardLabelsAction => ({
type: ActionTypes.AddDashboardLabels,
payload: {dashboardID, labels},
label: Label
): AddDashboardLabelAction => ({
type: ActionTypes.AddDashboardLabel,
payload: {dashboardID, label},
})
export const removeDashboardLabels = (
export const removeDashboardLabel = (
dashboardID: string,
labels: Label[]
): RemoveDashboardLabelsAction => ({
type: ActionTypes.RemoveDashboardLabels,
payload: {dashboardID, labels},
label: Label
): RemoveDashboardLabelAction => ({
type: ActionTypes.RemoveDashboardLabel,
payload: {dashboardID, label},
})
// Thunks
@ -262,6 +298,46 @@ export const createDashboard = () => async (
}
}
export const cloneUtilFunc = async (dash: Dashboard, id: string) => {
const cells = dash.cells
const pendingViews = cells.map(cell =>
apiGetDashboardsCellsView({
dashboardID: dash.id,
cellID: cell.id,
}).then(res => {
return {
...res,
cellID: cell.id,
}
})
)
const views = await Promise.all(pendingViews)
if (views.length > 0 && views.some(v => v.status !== 200)) {
throw new Error('An error occurred cloning the dashboard')
}
return views.map(async v => {
const view = v.data as View
const cell = cells.find(c => c.id === view.id)
if (cell && id) {
const newCell = await apiPostDashboardsCell({
dashboardID: id,
data: cell,
})
if (newCell.status !== 201) {
throw new Error('An error occurred cloning the dashboard')
}
return apiPatchDashboardsCellsView({
dashboardID: id,
cellID: newCell.data.id,
data: view,
})
}
})
}
export const cloneDashboard = (dashboard: Dashboard) => async (
dispatch,
getState: GetState
@ -274,10 +350,49 @@ export const cloneDashboard = (dashboard: Dashboard) => async (
const clonedName = incrementCloneName(allDashboardNames, dashboard.name)
const data = await client.dashboards.clone(dashboard.id, clonedName, org.id)
const getResp = await apiGetDashboard({dashboardID: dashboard.id})
if (getResp.status !== 200) {
throw new Error(getResp.data.message)
}
const dash = addDashboardDefaults(getResp.data)
const postResp = await apiPostDashboard({
data: {
orgID: org.id,
name: clonedName,
description: dash.description || '',
},
})
if (postResp.status !== 201) {
throw new Error(postResp.data.message)
}
const pendingLabels = dash.labels.map(l =>
apiPostDashboardsLabel({
dashboardID: postResp.data.id,
data: {labelID: l.id},
})
)
const mappedLabels = await Promise.all(pendingLabels)
if (mappedLabels.length > 0 && mappedLabels.some(l => l.status !== 201)) {
throw new Error('An error occurred cloning the labels for this dashboard')
}
const clonedViews = await cloneUtilFunc(dash, postResp.data.id)
const newViews = await Promise.all(clonedViews)
if (newViews.length > 0 && newViews.some(v => v.status !== 200)) {
throw new Error('An error occurred cloning the dashboard')
}
dispatch(checkDashboardLimits())
dispatch(push(`/orgs/${org.id}/dashboards/${data.id}`))
dispatch(push(`/orgs/${org.id}/dashboards/${postResp.data.id}`))
} catch (error) {
console.error(error)
if (isLimitError(error)) {
@ -414,7 +529,7 @@ export const createCellWithView = (
dashboard = await getDashboardAJAX(dashboardID)
}
const cell: CreateCell = getNewDashboardCell(dashboard, clonedCell)
const cell: NewCell = getNewDashboardCell(dashboard, clonedCell)
// Create the cell
const createdCell = await addCellAJAX(dashboardID, cell)
@ -519,31 +634,44 @@ export const copyDashboardCellAsync = (dashboard: Dashboard, cell: Cell) => (
}
}
export const addDashboardLabelsAsync = (
export const addDashboardLabelAsync = (
dashboardID: string,
labels: Label[]
label: Label
) => async (dispatch: Dispatch<Action | PublishNotificationAction>) => {
try {
const newLabels = await client.dashboards.addLabels(
const resp = await apiPostDashboardsLabel({
dashboardID,
labels.map(l => l.id)
)
data: {labelID: label.id},
})
dispatch(addDashboardLabels(dashboardID, newLabels))
if (resp.status !== 201) {
throw new Error(resp.data.message)
}
const lab = addLabelDefaults(resp.data.label)
dispatch(addDashboardLabel(dashboardID, lab))
} catch (error) {
console.error(error)
dispatch(notify(copy.addDashboardLabelFailed()))
}
}
export const removeDashboardLabelsAsync = (
export const removeDashboardLabelAsync = (
dashboardID: string,
labels: Label[]
label: Label
) => async (dispatch: Dispatch<Action | PublishNotificationAction>) => {
try {
await client.dashboards.removeLabels(dashboardID, labels.map(l => l.id))
const resp = await apiDeleteDashboardsLabel({
dashboardID,
labelID: label.id,
})
dispatch(removeDashboardLabels(dashboardID, labels))
if (resp.status !== 204) {
throw new Error(resp.data.message)
}
dispatch(removeDashboardLabel(dashboardID, label))
} catch (error) {
console.error(error)
dispatch(notify(copy.removedDashboardLabelFailed()))

View File

@ -2,67 +2,62 @@
import _ from 'lodash'
// APIs
import * as api from 'src/client'
import {
getDashboards as apiGetDashboards,
getDashboard as apiGetDashboard,
postDashboard as apiPostDashboard,
deleteDashboard as apiDeleteDashboard,
patchDashboard as apiPatchDashboard,
postDashboardsCell as apiPostDashboardsCell,
putDashboardsCells as apiPutDashboardsCells,
deleteDashboardsCell as apiDeleteDashboardsCell,
getDashboardsCellsView as apiGetDashboardsCellsView,
patchDashboardsCellsView as apiPatchDashboardsCellsView,
} from 'src/client'
// Types
import {Cell, NewCell, Dashboard, View, CreateDashboardRequest} from 'src/types'
export const addDashboardIDToCells = (
cells: Cell[],
dashboardID: string
): Cell[] => {
return cells.map(c => {
return {...c, dashboardID}
})
}
// Utils
import {
addDashboardDefaults,
addDashboardIDToCells,
} from 'src/dashboards/actions'
export const getDashboards = async (orgID: string): Promise<Dashboard[]> => {
const resp = await api.getDashboards({query: {orgID}})
const resp = await apiGetDashboards({query: {orgID}})
if (resp.status !== 200) {
throw new Error(resp.data.message)
}
return resp.data.dashboards.map(d => ({
...d,
cells: addDashboardIDToCells(d.cells as Cell[], d.id),
}))
return resp.data.dashboards.map(d => addDashboardDefaults(d))
}
export const getDashboard = async (id: string): Promise<Dashboard> => {
const resp = await api.getDashboard({dashboardID: id})
const resp = await apiGetDashboard({dashboardID: id})
if (resp.status !== 200) {
throw new Error(resp.data.message)
}
const dashboard = resp.data
return {
...dashboard,
cells: addDashboardIDToCells(dashboard.cells as Cell[], dashboard.id),
}
return addDashboardDefaults(resp.data)
}
export const createDashboard = async (
props: CreateDashboardRequest
): Promise<Dashboard> => {
const resp = await api.postDashboard({data: props})
const resp = await apiPostDashboard({data: props})
if (resp.status !== 201) {
throw new Error(resp.data.message)
}
const dashboard = resp.data
return {
...dashboard,
cells: addDashboardIDToCells(dashboard.cells as Cell[], dashboard.id),
}
return addDashboardDefaults(resp.data)
}
export const deleteDashboard = async (dashboard: Dashboard): Promise<void> => {
const resp = await api.deleteDashboard({dashboardID: dashboard.id})
const resp = await apiDeleteDashboard({dashboardID: dashboard.id})
if (resp.status !== 204) {
throw new Error(resp.data.message)
@ -72,7 +67,7 @@ export const deleteDashboard = async (dashboard: Dashboard): Promise<void> => {
export const updateDashboard = async (
dashboard: Dashboard
): Promise<Dashboard> => {
const resp = await api.patchDashboard({
const resp = await apiPatchDashboard({
dashboardID: dashboard.id,
data: dashboard,
})
@ -81,19 +76,14 @@ export const updateDashboard = async (
throw new Error(resp.data.message)
}
const updated = resp.data
return {
...updated,
cells: addDashboardIDToCells(updated.cells as Cell[], updated.id),
}
return addDashboardDefaults(resp.data)
}
export const addCell = async (
dashboardID: string,
cell: NewCell
): Promise<Cell> => {
const resp = await api.postDashboardsCell({dashboardID, data: cell})
const resp = await apiPostDashboardsCell({dashboardID, data: cell})
if (resp.status !== 201) {
throw new Error(resp.data.message)
@ -110,7 +100,7 @@ export const updateCells = async (
id: string,
cells: Cell[]
): Promise<Cell[]> => {
const resp = await api.putDashboardsCells({dashboardID: id, data: cells})
const resp = await apiPutDashboardsCells({dashboardID: id, data: cells})
if (resp.status !== 200) {
throw new Error(resp.data.message)
@ -118,14 +108,14 @@ export const updateCells = async (
const result = resp.data.cells
return addDashboardIDToCells(result as Cell[], id)
return addDashboardIDToCells(result, id)
}
export const deleteCell = async (
dashboardID: string,
cell: Cell
): Promise<void> => {
const resp = await api.deleteDashboardsCell({dashboardID, cellID: cell.id})
const resp = await apiDeleteDashboardsCell({dashboardID, cellID: cell.id})
if (resp.status !== 204) {
throw new Error(resp.data.message)
@ -136,15 +126,13 @@ export const getView = async (
dashboardID: string,
cellID: string
): Promise<View> => {
const resp = await api.getDashboardsCellsView({dashboardID, cellID})
const resp = await apiGetDashboardsCellsView({dashboardID, cellID})
if (resp.status !== 200) {
throw new Error(resp.data.message)
}
const view: View = {...resp.data, dashboardID, cellID}
return view
return {...resp.data, dashboardID, cellID}
}
export const updateView = async (
@ -152,7 +140,7 @@ export const updateView = async (
cellID: string,
view: Partial<View>
): Promise<View> => {
const resp = await api.patchDashboardsCellsView({
const resp = await apiPatchDashboardsCellsView({
dashboardID,
cellID,
data: view as View,

View File

@ -10,8 +10,8 @@ import InlineLabels from 'src/shared/components/inlineLabels/InlineLabels'
// Actions
import {
addDashboardLabelsAsync,
removeDashboardLabelsAsync,
addDashboardLabelAsync,
removeDashboardLabelAsync,
} from 'src/dashboards/actions'
import {createLabel as createLabelAsync} from 'src/labels/actions'
@ -41,8 +41,8 @@ interface StateProps {
}
interface DispatchProps {
onAddDashboardLabels: typeof addDashboardLabelsAsync
onRemoveDashboardLabels: typeof removeDashboardLabelsAsync
onAddDashboardLabel: typeof addDashboardLabelAsync
onRemoveDashboardLabel: typeof removeDashboardLabelAsync
onCreateLabel: typeof createLabelAsync
onResetViews: typeof resetViews
}
@ -78,7 +78,7 @@ class DashboardCard extends PureComponent<Props> {
}
labels={
<InlineLabels
selectedLabels={dashboard.labels as Label[]}
selectedLabels={dashboard.labels}
labels={labels}
onFilterChange={onFilterChange}
onAddLabel={this.handleAddLabel}
@ -162,15 +162,15 @@ class DashboardCard extends PureComponent<Props> {
}
private handleAddLabel = (label: Label) => {
const {dashboard, onAddDashboardLabels} = this.props
const {dashboard, onAddDashboardLabel} = this.props
onAddDashboardLabels(dashboard.id, [label])
onAddDashboardLabel(dashboard.id, label)
}
private handleRemoveLabel = (label: Label) => {
const {dashboard, onRemoveDashboardLabels} = this.props
const {dashboard, onRemoveDashboardLabel} = this.props
onRemoveDashboardLabels(dashboard.id, [label])
onRemoveDashboardLabel(dashboard.id, label)
}
private handleCreateLabel = async (label: Label) => {
@ -196,8 +196,8 @@ const mstp = ({labels}: AppState): StateProps => {
const mdtp: DispatchProps = {
onCreateLabel: createLabelAsync,
onAddDashboardLabels: addDashboardLabelsAsync,
onRemoveDashboardLabels: removeDashboardLabelsAsync,
onAddDashboardLabel: addDashboardLabelAsync,
onRemoveDashboardLabel: removeDashboardLabelAsync,
onResetViews: resetViews,
}

View File

@ -8,8 +8,8 @@ import {
removeDashboard,
editDashboard,
removeCell,
addDashboardLabels,
removeDashboardLabels,
addDashboardLabel,
removeDashboardLabel,
} from 'src/dashboards/actions/'
// Resources
@ -69,10 +69,10 @@ describe('dashboards reducer', () => {
it('can add labels to a dashboard', () => {
const dashboardWithoutLabels = {...dashboard, labels: []}
const expected = {status, list: [{...dashboard, labels}]}
const expected = {status, list: [{...dashboard, labels: [labels[0]]}]}
const actual = reducer(
{status, list: [dashboardWithoutLabels]},
addDashboardLabels(dashboardWithoutLabels.id, labels)
addDashboardLabel(dashboardWithoutLabels.id, labels[0])
)
expect(actual).toEqual(expected)
@ -82,12 +82,12 @@ describe('dashboards reducer', () => {
const leftOverLabel = {...labels[0], name: 'wowowowo', id: '3'}
const dashboardWithLabels = {
...dashboard,
labels: [...labels, leftOverLabel],
labels: [labels[0], leftOverLabel],
}
const expected = {status, list: [{...dashboard, labels: [leftOverLabel]}]}
const actual = reducer(
{status, list: [dashboardWithLabels]},
removeDashboardLabels(dashboardWithLabels.id, labels)
removeDashboardLabel(dashboardWithLabels.id, labels[0])
)
expect(actual).toEqual(expected)

View File

@ -74,12 +74,12 @@ export const dashboardsReducer = (
return
}
case ActionTypes.AddDashboardLabels: {
const {dashboardID, labels} = action.payload
case ActionTypes.AddDashboardLabel: {
const {dashboardID, label} = action.payload
draftState.list = draftState.list.map(d => {
if (d.id === dashboardID) {
d.labels = [...d.labels, ...labels]
d.labels = [...d.labels, label]
}
return d
@ -88,15 +88,11 @@ export const dashboardsReducer = (
return
}
case ActionTypes.RemoveDashboardLabels: {
const {dashboardID, labels} = action.payload
case ActionTypes.RemoveDashboardLabel: {
const {dashboardID, label} = action.payload
draftState.list = draftState.list.map(d => {
if (d.id === dashboardID) {
const updatedLabels = d.labels.filter(el => {
const labelToRemove = labels.find(l => l.id === el.id)
return !labelToRemove
})
const updatedLabels = d.labels.filter(el => !(label.id === el.id))
d.labels = updatedLabels
}

View File

@ -1,5 +1,4 @@
import {Dashboard} from '@influxdata/influx'
import {DashboardSwitcherLinks} from 'src/types/dashboards'
import {Dashboard, DashboardSwitcherLinks} from 'src/types'
export const EMPTY_LINKS = {
links: [],

View File

@ -8,7 +8,7 @@ import {Button, ComponentColor, ComponentSize} from '@influxdata/clockface'
import {ErrorHandling} from 'src/shared/decorators/errors'
// Types
import {Dashboard} from '@influxdata/influx'
import {Dashboard} from 'src/types'
interface OwnProps {
dashboards: Dashboard[]

View File

@ -31,8 +31,8 @@ import {
Columns,
Grid,
} from '@influxdata/clockface'
import {Organization} from 'src/types'
import {Dashboard, ScraperTargetRequest} from '@influxdata/influx'
import {Dashboard, Organization} from 'src/types'
import {ScraperTargetRequest} from '@influxdata/influx'
import {OnboardingStepProps} from 'src/onboarding/containers/OnboardingWizard'
import {QUICKSTART_SCRAPER_TARGET_URL} from 'src/dataLoaders/constants/pluginConfigs'

View File

@ -1,8 +1,12 @@
import {client} from 'src/utils/api'
// API
import {getDashboards as apiGetDashboards} from 'src/client'
// Types
import {Dashboard, Organization} from 'src/types'
// Utils
import {addDashboardDefaults} from 'src/dashboards/actions'
// CRUD APIs for Organizations and Organization resources
// i.e. Organization Members, Buckets, Dashboards etc
@ -12,12 +16,18 @@ export const getDashboards = async (
try {
let result
if (org) {
result = await client.dashboards.getAll(org.id)
result = await apiGetDashboards({query: {orgID: org.id}})
} else {
result = await client.dashboards.getAll()
result = await apiGetDashboards({})
}
return result
if (result.status !== 200) {
throw new Error(result.data.message)
}
const dashboards = result.data.map(d => addDashboardDefaults(d))
return dashboards
} catch (error) {
console.error('Could not get buckets for org', error)
throw error

View File

@ -4,9 +4,16 @@ import {getDeep} from 'src/utils/wrappers'
import {defaultBuilderConfig} from 'src/shared/utils/view'
import {viewableLabels} from 'src/labels/selectors'
import {Task, Label, Dashboard, Cell, View, Variable} from 'src/types'
import {
Task,
Label,
Dashboard,
DashboardQuery,
Cell,
View,
Variable,
} from 'src/types'
import {TemplateType, DocumentCreate, ITemplate} from '@influxdata/influx'
import {DashboardQuery} from 'src/types/dashboards'
const CURRENT_TEMPLATE_VERSION = '1'

View File

@ -20,6 +20,7 @@ import {addLabelDefaults} from 'src/labels/utils'
// API
import {
getDashboard as apiGetDashboard,
getTask as apiGetTask,
postTask as apiPostTask,
postTasksLabel as apiPostTasksLabel,
@ -29,30 +30,36 @@ import {
getVariables as apiGetVariables,
postVariable as apiPostVariable,
postVariablesLabel as apiPostVariablesLabel,
postDashboard as apiPostDashboard,
postDashboardsLabel as apiPostDashboardsLabel,
postDashboardsCell as apiPostDashboardsCell,
patchDashboardsCellsView as apiPatchDashboardsCellsView,
} from 'src/client'
import {client} from 'src/utils/api'
import {addDashboardDefaults} from 'src/dashboards/actions'
// Create Dashboard Templates
// Types
import {
TaskEntities,
DashboardTemplate,
Dashboard,
TemplateType,
Cell,
CellIncluded,
LabelIncluded,
ViewIncluded,
TaskTemplate,
TemplateBase,
TaskEntities,
Task,
VariableTemplate,
Variable,
} from 'src/types'
import {IDashboard, Cell} from '@influxdata/influx'
// Create Dashboard Templates
export const createDashboardFromTemplate = async (
template: DashboardTemplate,
orgID: string
): Promise<IDashboard> => {
): Promise<Dashboard> => {
const {content} = template
if (
@ -62,15 +69,19 @@ export const createDashboardFromTemplate = async (
throw new Error('Cannot create dashboard from this template')
}
const createdDashboard = await client.dashboards.create({
...content.data.attributes,
orgID,
const resp = await apiPostDashboard({
data: {
orgID,
...content.data.attributes,
},
})
if (!createdDashboard || !createdDashboard.id) {
throw new Error('Failed to create dashboard from template')
if (resp.status !== 201) {
throw new Error(resp.data.message)
}
const createdDashboard = addDashboardDefaults(resp.data)
// associate imported label id with new label
const labelMap = await createLabelsFromTemplate(template, orgID)
@ -81,19 +92,36 @@ export const createDashboardFromTemplate = async (
await createVariablesFromTemplate(template, labelMap, orgID)
const dashboard = await client.dashboards.get(createdDashboard.id)
const getResp = await apiGetDashboard({dashboardID: resp.data.id})
if (getResp.status !== 200) {
throw new Error(getResp.data.message)
}
const dashboard = addDashboardDefaults(getResp.data)
return dashboard
}
const addDashboardLabelsFromTemplate = async (
template: DashboardTemplate,
labelMap: LabelMap,
dashboard: IDashboard
dashboard: Dashboard
) => {
const labelRelationships = getLabelRelationships(template.content.data)
const labelIDs = labelRelationships.map(l => labelMap[l.id] || '')
await client.dashboards.addLabels(dashboard.id, labelIDs)
try {
const labelRelationships = getLabelRelationships(template.content.data)
const labelIDs = labelRelationships.map(l => labelMap[l.id] || '')
const pending = labelIDs.map(labelID =>
apiPostDashboardsLabel({dashboardID: dashboard.id, data: {labelID}})
)
const resolved = await Promise.all(pending)
if (resolved.length > 0 && resolved.some(r => r.status !== 201)) {
throw new Error(
'An error occurred adding dashboard labels from the template'
)
}
} catch (e) {
console.error(e)
}
}
type LabelMap = {[importedID: string]: CreatedLabelID}
@ -166,7 +194,7 @@ const createLabelsFromTemplate = async <T extends TemplateBase>(
const createCellsFromTemplate = async (
template: DashboardTemplate,
createdDashboard: IDashboard
createdDashboard: Dashboard
) => {
const {
content: {data, included},
@ -187,14 +215,23 @@ const createCellsFromTemplate = async (
const {
attributes: {x, y, w, h},
} = c
return client.dashboards.createCell(createdDashboard.id, {x, y, w, h})
return apiPostDashboardsCell({
dashboardID: createdDashboard.id,
data: {x, y, w, h},
})
})
const cellResponses = await Promise.all(pendingCells)
if (cellResponses.length > 0 && cellResponses.some(r => r.status !== 201)) {
throw new Error('An error occurred creating cells from the templates')
}
const responses = cellResponses.map(resp => resp.data as Cell)
createViewsFromTemplate(
template,
cellResponses,
responses,
cellsToCreate,
createdDashboard.id
)
@ -220,11 +257,11 @@ const createViewsFromTemplate = async (
})
const pendingViews = viewsToCreate.map((v, i) => {
return client.dashboards.updateView(
return apiPatchDashboardsCellsView({
dashboardID,
cellResponses[i].id,
v.attributes
)
cellID: cellResponses[i].id,
data: v.attributes,
})
})
await Promise.all(pendingViews)

View File

@ -9,6 +9,7 @@ import {
RenamableField,
BuilderConfig,
} from 'src/client'
import {Label} from 'src/types'
export type FieldOption = RenamableField
@ -38,6 +39,7 @@ export type NewCell = Omit<Cell, 'id' | 'links' | 'dashboardID'>
export interface Dashboard extends Omit<GenDashboard, 'cells'> {
cells: Cell[]
labels: Label[]
}
export type Base = Axis['base']

View File

@ -1,11 +1,10 @@
import {
IDashboard,
ILabel,
DocumentListEntry,
Document,
DocumentMeta,
} from '@influxdata/influx'
import {View, Cell, Label, Variable} from 'src/types'
import {ILabel} from '@influxdata/influx'
import {Dashboard, View, Cell, Label, Variable} from 'src/types'
export enum TemplateType {
Label = 'label',
@ -129,7 +128,7 @@ interface TaskTemplateData extends TemplateData {
interface DashboardTemplateData extends TemplateData {
type: TemplateType.Dashboard
attributes: IDashboard
attributes: Dashboard
relationships: {
[TemplateType.Label]: {data: LabelRelationship[]}
[TemplateType.Cell]: {data: CellRelationship[]}