chore(ui): refactored dashboards client API to oats generated types and API (#16438)
chore(ui): refactored dashboards to use oats generated api rather than clientpull/16520/head
parent
3b62340b31
commit
03335cceb9
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: [],
|
||||
|
|
|
|||
|
|
@ -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[]
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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[]}
|
||||
|
|
|
|||
Loading…
Reference in New Issue