Port dashboard from template function to ui from client
parent
7ae219ed35
commit
dcc7f93edb
|
@ -985,9 +985,9 @@
|
|||
}
|
||||
},
|
||||
"@influxdata/influx": {
|
||||
"version": "0.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@influxdata/influx/-/influx-0.2.47.tgz",
|
||||
"integrity": "sha512-yvq/aiU1EG7jHbU+k1cBLg5qRAa8Q5tyaqkiLEcIzhFsbzk7LBJ1WVUrnkwO+fRBIIRs6E/Jm7Cfd1+XVd+uKA==",
|
||||
"version": "0.2.48",
|
||||
"resolved": "https://registry.npmjs.org/@influxdata/influx/-/influx-0.2.48.tgz",
|
||||
"integrity": "sha512-CIqUd3hdKa6qQrsqQR3x2+r4r0guETnfTrMWXZ6EDOU5rWwyc2kdrgCJGRviy3RCvtV7+wtrQ1FYd8KSHUR82w==",
|
||||
"requires": {
|
||||
"axios": "^0.18.0"
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@influxdata/clockface": "0.0.5",
|
||||
"@influxdata/influx": "0.2.47",
|
||||
"@influxdata/influx": "0.2.48",
|
||||
"@influxdata/react-custom-scrollbars": "4.3.8",
|
||||
"axios": "^0.18.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
|
|
|
@ -17,8 +17,7 @@ import {
|
|||
getView as getViewAJAX,
|
||||
updateView as updateViewAJAX,
|
||||
} from 'src/dashboards/apis'
|
||||
|
||||
import {client} from 'src/utils/api'
|
||||
import {createDashboardFromTemplate as createDashboardFromTemplateAJAX} from 'src/templates/api'
|
||||
|
||||
// Actions
|
||||
import {notify} from 'src/shared/actions/notifications'
|
||||
|
@ -48,6 +47,7 @@ import {
|
|||
getClonedDashboardCell,
|
||||
} from 'src/dashboards/utils/cellGetters'
|
||||
import {dashboardToTemplate} from 'src/shared/utils/resourceToTemplate'
|
||||
import {client} from 'src/utils/api'
|
||||
|
||||
// Constants
|
||||
import * as copy from 'src/shared/copy/notifications'
|
||||
|
@ -55,8 +55,15 @@ import * as copy from 'src/shared/copy/notifications'
|
|||
// Types
|
||||
import {RemoteDataState} from 'src/types'
|
||||
import {PublishNotificationAction} from 'src/types/actions/notifications'
|
||||
import {CreateCell, IDashboardTemplate, ILabel} from '@influxdata/influx'
|
||||
import {Dashboard, NewView, Cell, GetState, View} from 'src/types/v2'
|
||||
import {
|
||||
Dashboard,
|
||||
NewView,
|
||||
Cell,
|
||||
GetState,
|
||||
View,
|
||||
DashboardTemplate,
|
||||
} from 'src/types/v2'
|
||||
import {CreateCell, ILabel} from '@influxdata/influx'
|
||||
|
||||
export enum ActionTypes {
|
||||
LoadDashboards = 'LOAD_DASHBOARDS',
|
||||
|
@ -218,11 +225,11 @@ export const getDashboardsAsync = () => async (
|
|||
}
|
||||
|
||||
export const createDashboardFromTemplate = (
|
||||
template: IDashboardTemplate,
|
||||
template: DashboardTemplate,
|
||||
orgID: string
|
||||
) => async dispatch => {
|
||||
try {
|
||||
await client.dashboards.createFromTemplate(template, orgID)
|
||||
await createDashboardFromTemplateAJAX(template, orgID)
|
||||
|
||||
dispatch(notify(importDashboardSucceeded()))
|
||||
} catch (error) {
|
||||
|
|
|
@ -24,6 +24,9 @@ import {
|
|||
import {createDashboardsForPlugins as createDashboardsForPluginsAction} from 'src/protos/actions'
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
|
||||
// APIs
|
||||
import {createDashboardFromTemplate as createDashboardFromTemplateAJAX} from 'src/templates/api'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
TelegrafDashboardCreated,
|
||||
|
@ -31,10 +34,9 @@ import {
|
|||
} from 'src/shared/copy/notifications'
|
||||
|
||||
// Types
|
||||
import {AppState} from 'src/types/v2/index'
|
||||
import {AppState, DashboardTemplate} from 'src/types/v2/index'
|
||||
import {TelegrafPlugin, ConfigurationState} from 'src/types/v2/dataLoaders'
|
||||
import {client} from 'src/utils/api'
|
||||
import {IDashboardTemplate} from '@influxdata/influx'
|
||||
|
||||
interface DispatchProps {
|
||||
onSetTelegrafConfigName: typeof setTelegrafConfigName
|
||||
|
@ -165,7 +167,7 @@ export class TelegrafPluginInstructions extends PureComponent<Props> {
|
|||
const templates = await Promise.all(pendingTemplates)
|
||||
|
||||
const pendingDashboards = templates.map(t =>
|
||||
client.dashboards.createFromTemplate(t as IDashboardTemplate, orgID)
|
||||
createDashboardFromTemplateAJAX(t as DashboardTemplate, orgID)
|
||||
)
|
||||
|
||||
const dashboards = await Promise.all(pendingDashboards)
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
import _ from 'lodash'
|
||||
import {
|
||||
DashboardTemplate,
|
||||
TemplateType,
|
||||
CellIncluded,
|
||||
LabelIncluded,
|
||||
ViewIncluded,
|
||||
} from 'src/types/v2'
|
||||
import {IDashboard, Cell} from '@influxdata/influx'
|
||||
import {client} from 'src/utils/api'
|
||||
|
||||
import {
|
||||
findIncludedsFromRelationships,
|
||||
findLabelIDsToAdd,
|
||||
findLabelsToCreate,
|
||||
findIncludedFromRelationship,
|
||||
findVariablesToCreate,
|
||||
findIncludedVariables,
|
||||
} from 'src/templates/utils/'
|
||||
|
||||
// Create Dashboard Templates
|
||||
|
||||
export const createDashboardFromTemplate = async (
|
||||
template: DashboardTemplate,
|
||||
orgID: string
|
||||
): Promise<IDashboard> => {
|
||||
const {content} = template
|
||||
|
||||
if (
|
||||
content.data.type !== TemplateType.Dashboard ||
|
||||
template.meta.version !== '1'
|
||||
) {
|
||||
throw new Error('Can not create dashboard from this template')
|
||||
}
|
||||
|
||||
const createdDashboard = await client.dashboards.create({
|
||||
...content.data.attributes,
|
||||
orgID,
|
||||
})
|
||||
|
||||
if (!createdDashboard || !createdDashboard.id) {
|
||||
throw new Error('Failed to create dashboard from template')
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
await createLabelsFromTemplate(template, createdDashboard),
|
||||
await createCellsFromTemplate(template, createdDashboard),
|
||||
])
|
||||
createVariablesFromTemplate(template, orgID)
|
||||
|
||||
const dashboard = await client.dashboards.get(createdDashboard.id)
|
||||
return dashboard
|
||||
}
|
||||
|
||||
const createLabelsFromTemplate = async (
|
||||
template: DashboardTemplate,
|
||||
dashboard: IDashboard
|
||||
) => {
|
||||
const {
|
||||
content: {data, included},
|
||||
} = template
|
||||
|
||||
if (!data.relationships || !data.relationships[TemplateType.Label]) {
|
||||
return
|
||||
}
|
||||
|
||||
const labelRelationships = data.relationships[TemplateType.Label].data
|
||||
|
||||
const labelsIncluded = findIncludedsFromRelationships<LabelIncluded>(
|
||||
included,
|
||||
labelRelationships
|
||||
)
|
||||
|
||||
const existingLabels = await client.labels.getAll()
|
||||
|
||||
const labelsToCreate = findLabelsToCreate(existingLabels, labelsIncluded).map(
|
||||
l => ({
|
||||
name: _.get(l, 'attributes.name', ''),
|
||||
properties: _.get(l, 'attributes.properties', {}),
|
||||
orgID: dashboard.orgID,
|
||||
})
|
||||
)
|
||||
|
||||
const createdLabels = await client.labels.createAll(labelsToCreate)
|
||||
|
||||
// IDs of newly created labels that should be added to dashboard
|
||||
const createdLabelIDs = createdLabels.map(l => l.id || '')
|
||||
|
||||
// IDs of existing labels that should be added to dashboard
|
||||
const existingLabelIDs = findLabelIDsToAdd(existingLabels, labelsIncluded)
|
||||
|
||||
await client.dashboards.addLabels(dashboard.id, [
|
||||
...createdLabelIDs,
|
||||
...existingLabelIDs,
|
||||
])
|
||||
}
|
||||
|
||||
const createCellsFromTemplate = async (
|
||||
template: DashboardTemplate,
|
||||
createdDashboard: IDashboard
|
||||
) => {
|
||||
const {
|
||||
content: {data, included},
|
||||
} = template
|
||||
|
||||
if (!data.relationships || !data.relationships[TemplateType.Cell]) {
|
||||
return
|
||||
}
|
||||
|
||||
const cellRelationships = data.relationships[TemplateType.Cell].data
|
||||
|
||||
const cellsToCreate = findIncludedsFromRelationships<CellIncluded>(
|
||||
included,
|
||||
cellRelationships
|
||||
)
|
||||
|
||||
const pendingCells = cellsToCreate.map(c => {
|
||||
const {
|
||||
attributes: {x, y, w, h},
|
||||
} = c
|
||||
return client.dashboards.createCell(createdDashboard.id, {x, y, w, h})
|
||||
})
|
||||
|
||||
const cellResponses = await Promise.all(pendingCells)
|
||||
|
||||
createViewsFromTemplate(
|
||||
template,
|
||||
cellResponses,
|
||||
cellsToCreate,
|
||||
createdDashboard.id
|
||||
)
|
||||
}
|
||||
|
||||
const createViewsFromTemplate = async (
|
||||
template: DashboardTemplate,
|
||||
cellResponses: Cell[],
|
||||
cellsToCreate: CellIncluded[],
|
||||
dashboardID: string
|
||||
) => {
|
||||
const viewsToCreate = cellsToCreate.map(c => {
|
||||
const {
|
||||
content: {included},
|
||||
} = template
|
||||
|
||||
const viewRelationship = c.relationships[TemplateType.View].data
|
||||
|
||||
return findIncludedFromRelationship<ViewIncluded>(
|
||||
included,
|
||||
viewRelationship
|
||||
)
|
||||
})
|
||||
|
||||
const pendingViews = viewsToCreate.map((v, i) => {
|
||||
return client.dashboards.updateView(
|
||||
dashboardID,
|
||||
cellResponses[i].id,
|
||||
v.attributes
|
||||
)
|
||||
})
|
||||
|
||||
await Promise.all(pendingViews)
|
||||
}
|
||||
|
||||
const createVariablesFromTemplate = async (
|
||||
template: DashboardTemplate,
|
||||
orgID: string
|
||||
) => {
|
||||
const {
|
||||
content: {data, included},
|
||||
} = template
|
||||
if (!data.relationships || !data.relationships[TemplateType.Variable]) {
|
||||
return
|
||||
}
|
||||
const variablesIncluded = findIncludedVariables(included)
|
||||
|
||||
const existingVariables = await client.variables.getAll()
|
||||
|
||||
const variablesToCreate = findVariablesToCreate(
|
||||
existingVariables,
|
||||
variablesIncluded
|
||||
).map(v => ({...v.attributes, orgID}))
|
||||
|
||||
await client.variables.createAll(variablesToCreate)
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
import {
|
||||
ILabel,
|
||||
Variable,
|
||||
IDashboard,
|
||||
DocumentListEntry,
|
||||
Document,
|
||||
} from '@influxdata/influx'
|
||||
import {View, Cell} from 'src/types/v2'
|
||||
|
||||
export enum TemplateType {
|
||||
Label = 'label',
|
||||
Task = 'task',
|
||||
Dashboard = 'dashboard',
|
||||
View = 'view',
|
||||
Cell = 'cell',
|
||||
Variable = 'variable',
|
||||
}
|
||||
|
||||
interface KeyValuePairs {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
// Templates
|
||||
interface TemplateBase extends Document {
|
||||
content: {data: TemplateData; included: TemplateIncluded[]}
|
||||
labels?: ILabel[]
|
||||
}
|
||||
|
||||
// TODO: be more specific about what attributes can be
|
||||
interface TemplateData {
|
||||
type: TemplateType
|
||||
attributes: KeyValuePairs
|
||||
relationships: {[key in TemplateType]?: {data: IRelationship[]}}
|
||||
}
|
||||
|
||||
interface TemplateIncluded {
|
||||
type: TemplateType
|
||||
id: string
|
||||
attributes: KeyValuePairs
|
||||
}
|
||||
|
||||
// Template Relationships
|
||||
type IRelationship =
|
||||
| CellRelationship
|
||||
| LabelRelationship
|
||||
| ViewRelationship
|
||||
| VariableRelationship
|
||||
|
||||
export interface CellRelationship {
|
||||
type: TemplateType.Cell
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface LabelRelationship {
|
||||
type: TemplateType.Label
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface VariableRelationship {
|
||||
type: TemplateType.Variable
|
||||
id: string
|
||||
}
|
||||
|
||||
interface ViewRelationship {
|
||||
type: TemplateType.View
|
||||
id: string
|
||||
}
|
||||
|
||||
// Template Includeds
|
||||
export interface ViewIncluded extends TemplateIncluded {
|
||||
type: TemplateType.View
|
||||
attributes: View
|
||||
}
|
||||
|
||||
export interface CellIncluded extends TemplateIncluded {
|
||||
type: TemplateType.Cell
|
||||
attributes: Cell
|
||||
relationships: {
|
||||
[TemplateType.View]: {data: ViewRelationship}
|
||||
}
|
||||
}
|
||||
|
||||
export interface LabelIncluded extends TemplateIncluded {
|
||||
type: TemplateType.Label
|
||||
attributes: ILabel
|
||||
}
|
||||
|
||||
export interface VariableIncluded extends TemplateIncluded {
|
||||
type: TemplateType.Variable
|
||||
attributes: Variable
|
||||
}
|
||||
|
||||
export type TaskTemplateIncluded = LabelIncluded
|
||||
|
||||
export type DashboardTemplateIncluded =
|
||||
| CellIncluded
|
||||
| ViewIncluded
|
||||
| LabelIncluded
|
||||
| VariableIncluded
|
||||
|
||||
// Template Datas
|
||||
interface TaskTemplateData extends TemplateData {
|
||||
type: TemplateType.Task
|
||||
attributes: {name: string; flux: string}
|
||||
relationships: {
|
||||
[TemplateType.Label]: {data: LabelRelationship[]}
|
||||
}
|
||||
}
|
||||
|
||||
interface DashboardTemplateData extends TemplateData {
|
||||
type: TemplateType.Dashboard
|
||||
attributes: IDashboard
|
||||
relationships: {
|
||||
[TemplateType.Label]: {data: LabelRelationship[]}
|
||||
[TemplateType.Cell]: {data: CellRelationship[]}
|
||||
[TemplateType.Variable]: {data: VariableRelationship[]}
|
||||
}
|
||||
}
|
||||
|
||||
// Templates
|
||||
export interface TaskTemplate extends TemplateBase {
|
||||
content: {
|
||||
data: TaskTemplateData
|
||||
included: TaskTemplateIncluded[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface DashboardTemplate extends TemplateBase {
|
||||
content: {
|
||||
data: DashboardTemplateData
|
||||
included: DashboardTemplateIncluded[]
|
||||
}
|
||||
}
|
||||
|
||||
export type Template = TaskTemplate | DashboardTemplate
|
||||
|
||||
export interface TemplateSummary extends DocumentListEntry {
|
||||
labels: ILabel[]
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import {
|
||||
findIncludedsFromRelationships,
|
||||
findIncludedFromRelationship,
|
||||
findIncludedVariables,
|
||||
} from 'src/templates/utils/'
|
||||
import {TemplateType} from 'src/types/v2'
|
||||
|
||||
const includeds = [
|
||||
{type: TemplateType.Cell, id: '1', attributes: {id: 'a'}},
|
||||
{type: TemplateType.View, id: '3'},
|
||||
{type: TemplateType.Variable, id: '3'},
|
||||
{type: TemplateType.Variable, id: '1'},
|
||||
]
|
||||
const relationships = [{type: TemplateType.Cell, id: '1'}]
|
||||
|
||||
describe('Templates utils', () => {
|
||||
describe('findIncludedsFromRelationships', () => {
|
||||
it('finds item in included that matches relationship', () => {
|
||||
const actual = findIncludedsFromRelationships(includeds, relationships)
|
||||
const expected = [
|
||||
{type: TemplateType.Cell, id: '1', attributes: {id: 'a'}},
|
||||
]
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('findIncludedFromRelationship', () => {
|
||||
it('finds included that matches relationship', () => {
|
||||
const actual = findIncludedFromRelationship(includeds, relationships[0])
|
||||
const expected = {type: TemplateType.Cell, id: '1', attributes: {id: 'a'}}
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('findIncludedVariables', () => {
|
||||
it('finds included that matches relationship', () => {
|
||||
const actual = findIncludedVariables(includeds)
|
||||
const expected = [
|
||||
{type: TemplateType.Variable, id: '3'},
|
||||
{type: TemplateType.Variable, id: '1'},
|
||||
]
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,60 @@
|
|||
import {TemplateType, LabelIncluded, VariableIncluded} from 'src/types/v2'
|
||||
import {ILabel, Variable} from '@influxdata/influx'
|
||||
|
||||
export function findIncludedsFromRelationships<
|
||||
T extends {id: string; type: TemplateType}
|
||||
>(
|
||||
includeds: {id: string; type: TemplateType}[],
|
||||
relationships: {id: string; type: TemplateType}[]
|
||||
): T[] {
|
||||
let intersection = []
|
||||
relationships.forEach(r => {
|
||||
const included = findIncludedFromRelationship<T>(includeds, r)
|
||||
if (included) {
|
||||
intersection = [...intersection, included]
|
||||
}
|
||||
})
|
||||
return intersection
|
||||
}
|
||||
|
||||
export function findIncludedFromRelationship<
|
||||
T extends {id: string; type: TemplateType}
|
||||
>(
|
||||
includeds: {id: string; type: TemplateType}[],
|
||||
r: {id: string; type: TemplateType}
|
||||
): T {
|
||||
return includeds.find((i): i is T => i.id === r.id && i.type === r.type) as T
|
||||
}
|
||||
|
||||
export const findLabelIDsToAdd = (
|
||||
existingLabels: ILabel[],
|
||||
incomingLabels: LabelIncluded[]
|
||||
): string[] => {
|
||||
return existingLabels
|
||||
.filter(el => !!incomingLabels.find(l => el.name === l.attributes.name))
|
||||
.map(l => l.id || '')
|
||||
}
|
||||
|
||||
export const findLabelsToCreate = (
|
||||
currentLabels: ILabel[],
|
||||
labels: LabelIncluded[]
|
||||
): LabelIncluded[] => {
|
||||
return labels.filter(
|
||||
l => !currentLabels.find(el => el.name === l.attributes.name)
|
||||
)
|
||||
}
|
||||
|
||||
export const findIncludedVariables = (included: {type: TemplateType}[]) => {
|
||||
return included.filter(
|
||||
(r): r is VariableIncluded => r.type === TemplateType.Variable
|
||||
)
|
||||
}
|
||||
|
||||
export const findVariablesToCreate = (
|
||||
existingVariables: Variable[],
|
||||
incomingVariables: VariableIncluded[]
|
||||
): VariableIncluded[] => {
|
||||
return incomingVariables.filter(
|
||||
v => !existingVariables.find(ev => ev.name === v.attributes.name)
|
||||
)
|
||||
}
|
|
@ -43,6 +43,22 @@ import {TelegrafsState} from 'src/telegrafs/reducers'
|
|||
import {TemplatesState} from 'src/templates/reducers'
|
||||
import {AuthorizationsState} from 'src/authorizations/reducers'
|
||||
import {ScrapersState} from 'src/scrapers/reducers'
|
||||
import {
|
||||
TemplateType,
|
||||
LabelRelationship,
|
||||
VariableRelationship,
|
||||
CellRelationship,
|
||||
ViewIncluded,
|
||||
CellIncluded,
|
||||
LabelIncluded,
|
||||
VariableIncluded,
|
||||
TaskTemplateIncluded,
|
||||
DashboardTemplateIncluded,
|
||||
TaskTemplate,
|
||||
DashboardTemplate,
|
||||
TemplateSummary,
|
||||
Template,
|
||||
} from 'src/templates/types'
|
||||
|
||||
export interface AppState {
|
||||
VERSION: string
|
||||
|
@ -101,4 +117,18 @@ export {
|
|||
TaskStatus,
|
||||
MeState,
|
||||
Label,
|
||||
TemplateType,
|
||||
LabelRelationship,
|
||||
VariableRelationship,
|
||||
CellRelationship,
|
||||
ViewIncluded,
|
||||
CellIncluded,
|
||||
LabelIncluded,
|
||||
VariableIncluded,
|
||||
TaskTemplateIncluded,
|
||||
DashboardTemplateIncluded,
|
||||
TaskTemplate,
|
||||
DashboardTemplate,
|
||||
TemplateSummary,
|
||||
Template,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue