diff --git a/CHANGELOG.md b/CHANGELOG.md index 91b716350..148ee6760 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ 1. [#4404](https://github.com/influxdata/chronograf/pull/4404): Add loading status indicator to hosts page 1. [#4422](https://github.com/influxdata/chronograf/pull/4422): Allow deep linking flux script in data explorer 1. [#4410](https://github.com/influxdata/chronograf/pull/4410): Add ability to use line graph visualizations for flux query +1. [#4445](https://github.com/influxdata/chronograf/pull/4445): Allow flux dashboard cells to be exported ### UI Improvements diff --git a/ui/src/dashboards/containers/DashboardsPage.tsx b/ui/src/dashboards/containers/DashboardsPage.tsx index 48f26b87d..f6f708562 100644 --- a/ui/src/dashboards/containers/DashboardsPage.tsx +++ b/ui/src/dashboards/containers/DashboardsPage.tsx @@ -8,6 +8,7 @@ import DashboardsContents from 'src/dashboards/components/DashboardsPageContents import {Page} from 'src/reusable_ui' import {getDeep} from 'src/utils/wrappers' +import {mapDashboardForDownload} from 'src/dashboards/utils/export' import {createDashboard} from 'src/dashboards/apis' import { getDashboardsAsync, @@ -17,6 +18,7 @@ import { retainRangesDashTimeV1 as retainRangesDashTimeV1Action, } from 'src/dashboards/actions' import {notify as notifyAction} from 'src/shared/actions/notifications' +import {fetchAllFluxServicesAsync} from 'src/shared/actions/services' import { NEW_DASHBOARD, @@ -29,7 +31,7 @@ import { notifyDashboardExportFailed, } from 'src/shared/copy/notifications' -import {Source, Dashboard, RemoteDataState} from 'src/types' +import {Source, Dashboard, RemoteDataState, Service} from 'src/types' import {Notification} from 'src/types/notifications' import {DashboardFile, Cell} from 'src/types/dashboards' @@ -37,13 +39,16 @@ export interface Props { source: Source sources: Source[] router: InjectedRouter + dashboard: Dashboard handleGetDashboards: () => Promise handleGetChronografVersion: () => string handleDeleteDashboard: (dashboard: Dashboard) => void handleImportDashboard: (dashboard: Dashboard) => void notify: (message: Notification) => void retainRangesDashTimeV1: (dashboardIDs: number[]) => void + fetchAllFluxServices: (sources: Source[]) => Promise dashboards: Dashboard[] + services: Service[] } interface State { @@ -66,6 +71,8 @@ export class DashboardsPage extends PureComponent { try { dashboards = await this.props.handleGetDashboards() + await this.props.fetchAllFluxServices(this.props.sources) + const dashboardIDs = dashboards.map(d => d.id) this.props.retainRangesDashTimeV1(dashboardIDs) @@ -155,22 +162,10 @@ export class DashboardsPage extends PureComponent { private modifyDashboardForDownload = async ( dashboard: Dashboard ): Promise => { - const {sources} = this.props - const sourceMappings = _.reduce( - sources, - (acc, s) => { - const {name, id, links} = s - const link = _.get(links, 'self', '') - acc[id] = {name, link} - return acc - }, - {} - ) - const version = await this.props.handleGetChronografVersion() - return { - meta: {chronografVersion: version, sources: sourceMappings}, - dashboard, - } + const {sources, services, handleGetChronografVersion} = this.props + const version = await handleGetChronografVersion() + + return mapDashboardForDownload(sources, services, dashboard, version) } private handleImportDashboard = async ( @@ -191,10 +186,15 @@ export class DashboardsPage extends PureComponent { } } -const mapStateToProps = ({dashboardUI: {dashboards, dashboard}, sources}) => ({ +const mapStateToProps = ({ + dashboardUI: {dashboards, dashboard}, + sources, + services, +}): Partial => ({ dashboards, dashboard, sources, + services, }) const mapDispatchToProps = { @@ -204,6 +204,7 @@ const mapDispatchToProps = { handleImportDashboard: importDashboardAsync, notify: notifyAction, retainRangesDashTimeV1: retainRangesDashTimeV1Action, + fetchAllFluxServices: fetchAllFluxServicesAsync, } export default withRouter( diff --git a/ui/src/dashboards/utils/export.ts b/ui/src/dashboards/utils/export.ts new file mode 100644 index 000000000..62a74ed08 --- /dev/null +++ b/ui/src/dashboards/utils/export.ts @@ -0,0 +1,86 @@ +import _ from 'lodash' + +import {Source, Dashboard, Service, Cell} from 'src/types' +import {CellQuery} from 'src/types/dashboards' +import {DashboardFile} from 'src/types/dashboards' + +export const isFluxService = (link: string) => link.includes('service') + +export const mapServicesForDownload = (originalServices: Service[]) => + _.reduce( + originalServices, + (acc, service) => { + const {name, id, links, sourceID} = service + const link = _.get(links, 'self', '') + acc[id] = {name, link, sourceID} + return acc + }, + {} + ) + +export const mapSourcesForDownload = (originalSources: Source[]) => + _.reduce( + originalSources, + (acc, source) => { + const {name, id, links} = source + const link = _.get(links, 'self', '') + acc[id] = {name, link} + return acc + }, + {} + ) + +export const matchSourceLink = (cellQuery: CellQuery) => { + if (!isFluxService(cellQuery.source)) { + return cellQuery.source + } + + return null +} + +export const matchServiceLink = (cellQuery: CellQuery) => { + if (isFluxService(cellQuery.source)) { + return cellQuery.source + } + + return null +} + +export const mapQueriesToSources = (queries: CellQuery[]) => { + return queries.map(query => { + return { + ...query, + source: matchSourceLink(query), + service: matchServiceLink(query), + } + }) +} + +export const mapCellsToSources = (cells: Cell[]) => { + return cells.map(cell => { + const {queries} = cell + + return { + ...cell, + queries: mapQueriesToSources(queries), + } + }) +} + +export const mapDashboardForDownload = ( + originalSources: Source[], + originalServices: Service[], + originalDashboard: Dashboard, + chronografVersion: string +): DashboardFile => { + const sources = mapSourcesForDownload(originalSources) + const services = mapServicesForDownload(originalServices) + const meta = {chronografVersion, sources, services} + + const dashboard = { + ...originalDashboard, + cells: mapCellsToSources(originalDashboard.cells), + } + + return {meta, dashboard} +}