Merge pull request #3866 from influxdata/fix/hosts-dashboard-header
Fix hosts links renderingpull/10616/head
commit
4dab2232a3
|
@ -1,7 +1,18 @@
|
|||
import AJAX from 'src/utils/ajax'
|
||||
|
||||
import {
|
||||
linksFromDashboards,
|
||||
updateActiveDashboardLink,
|
||||
} from 'src/dashboards/utils/dashboardSwitcherLinks'
|
||||
|
||||
import {AxiosResponse} from 'axios'
|
||||
import {DashboardsResponse, GetDashboards} from 'src/types/apis/dashboards'
|
||||
import {
|
||||
DashboardsResponse,
|
||||
GetDashboards,
|
||||
LoadLinksOptions,
|
||||
} from 'src/types/apis/dashboards'
|
||||
import {DashboardSwitcherLinks} from 'src/types/dashboards'
|
||||
import {Source} from 'src/types/sources'
|
||||
|
||||
export const getDashboards: GetDashboards = () => {
|
||||
return AJAX<DashboardsResponse>({
|
||||
|
@ -10,6 +21,20 @@ export const getDashboards: GetDashboards = () => {
|
|||
}) as Promise<AxiosResponse<DashboardsResponse>>
|
||||
}
|
||||
|
||||
export const loadDashboardLinks = async (
|
||||
source: Source,
|
||||
{activeDashboard, dashboardsAJAX = getDashboards}: LoadLinksOptions
|
||||
): Promise<DashboardSwitcherLinks> => {
|
||||
const {
|
||||
data: {dashboards},
|
||||
} = await dashboardsAJAX()
|
||||
|
||||
const links = linksFromDashboards(dashboards, source)
|
||||
const dashboardLinks = updateActiveDashboardLink(links, activeDashboard)
|
||||
|
||||
return dashboardLinks
|
||||
}
|
||||
|
||||
export const getDashboard = async dashboardID => {
|
||||
try {
|
||||
return await AJAX({
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export const EMPTY_LINKS = {
|
||||
links: [],
|
||||
active: null,
|
||||
}
|
|
@ -24,7 +24,9 @@ import * as notifyActions from 'src/shared/actions/notifications'
|
|||
import idNormalizer, {TYPE_ID} from 'src/normalizers/id'
|
||||
import {millisecondTimeRange} from 'src/dashboards/utils/time'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
import * as dashboardSwitcher from 'src/dashboards/utils/dashboardSwitcherLinks'
|
||||
|
||||
// APIs
|
||||
import {loadDashboardLinks} from 'src/dashboards/apis'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
|
@ -34,6 +36,7 @@ import {
|
|||
TEMP_VAR_UPPER_DASHBOARD_TIME,
|
||||
} from 'src/shared/constants'
|
||||
import {FORMAT_INFLUXQL, defaultTimeRange} from 'src/shared/data/timeRanges'
|
||||
import {EMPTY_LINKS} from 'src/dashboards/constants/dashboardHeader'
|
||||
|
||||
// Types
|
||||
import {WithRouterProps} from 'react-router'
|
||||
|
@ -125,7 +128,7 @@ class DashboardPage extends Component<Props, State> {
|
|||
selectedCell: null,
|
||||
scrollTop: 0,
|
||||
windowHeight: window.innerHeight,
|
||||
dashboardLinks: dashboardSwitcher.EMPTY_LINKS,
|
||||
dashboardLinks: EMPTY_LINKS,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,14 +500,10 @@ class DashboardPage extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private getDashboardLinks = async (): Promise<void> => {
|
||||
const {source, dashboard} = this.props
|
||||
const {source, dashboard: activeDashboard} = this.props
|
||||
|
||||
try {
|
||||
const links = await dashboardSwitcher.loadDashboardLinks(source)
|
||||
const dashboardLinks = dashboardSwitcher.updateActiveDashboardLink(
|
||||
links,
|
||||
dashboard
|
||||
)
|
||||
const dashboardLinks = await loadDashboardLinks(source, {activeDashboard})
|
||||
|
||||
this.setState({
|
||||
dashboardLinks,
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
import {getDashboards} from 'src/dashboards/apis'
|
||||
|
||||
import {GetDashboards} from 'src/types/apis/dashboards'
|
||||
import {Source} from 'src/types/sources'
|
||||
import {Dashboard, DashboardSwitcherLinks} from 'src/types/dashboards'
|
||||
|
||||
|
@ -9,18 +6,7 @@ export const EMPTY_LINKS = {
|
|||
active: null,
|
||||
}
|
||||
|
||||
export const loadDashboardLinks = async (
|
||||
source: Source,
|
||||
dashboardsAJAX: GetDashboards = getDashboards
|
||||
): Promise<DashboardSwitcherLinks> => {
|
||||
const {
|
||||
data: {dashboards},
|
||||
} = await dashboardsAJAX()
|
||||
|
||||
return linksFromDashboards(dashboards, source)
|
||||
}
|
||||
|
||||
const linksFromDashboards = (
|
||||
export const linksFromDashboards = (
|
||||
dashboards: Dashboard[],
|
||||
source: Source
|
||||
): DashboardSwitcherLinks => {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import {proxy} from 'utils/queryUrlGenerator'
|
||||
import replaceTemplate from 'src/tempVars/utils/replace'
|
||||
import AJAX from 'utils/ajax'
|
||||
import {
|
||||
linksFromHosts,
|
||||
updateActiveHostLink,
|
||||
} from 'src/hosts/utils/hostsSwitcherLinks'
|
||||
import _ from 'lodash'
|
||||
|
||||
export const getCpuAndLoadForHosts = (
|
||||
|
@ -95,7 +99,12 @@ export const getCpuAndLoadForHosts = (
|
|||
})
|
||||
}
|
||||
|
||||
export async function getAllHosts(proxyLink, telegrafDB) {
|
||||
async function getAllHosts(source) {
|
||||
const {
|
||||
telegrafDB,
|
||||
links: {proxy: proxyLink},
|
||||
} = source
|
||||
|
||||
try {
|
||||
const resp = await proxy({
|
||||
source: proxyLink,
|
||||
|
@ -122,6 +131,16 @@ export async function getAllHosts(proxyLink, telegrafDB) {
|
|||
}
|
||||
}
|
||||
|
||||
export const loadHostsLinks = async (
|
||||
source,
|
||||
{activeHost = {}, getHostNamesAJAX = getAllHosts} = {}
|
||||
) => {
|
||||
const hostNames = await getHostNamesAJAX(source)
|
||||
const allLinks = linksFromHosts(hostNames, source)
|
||||
|
||||
return updateActiveHostLink(allLinks, activeHost)
|
||||
}
|
||||
|
||||
export const getLayouts = () =>
|
||||
AJAX({
|
||||
method: 'GET',
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import LayoutRenderer from 'shared/components/LayoutRenderer'
|
||||
|
@ -15,8 +14,9 @@ import {
|
|||
getLayouts,
|
||||
getAppsForHost,
|
||||
getMeasurementsForHost,
|
||||
getAllHosts,
|
||||
loadHostsLinks,
|
||||
} from 'src/hosts/apis'
|
||||
import {EMPTY_LINKS} from 'src/dashboards/constants/dashboardHeader'
|
||||
|
||||
import {setAutoRefresh, delayEnablePresentationMode} from 'shared/actions/app'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -27,7 +27,7 @@ class HostPage extends Component {
|
|||
super(props)
|
||||
this.state = {
|
||||
layouts: [],
|
||||
hosts: {},
|
||||
hostLinks: EMPTY_LINKS,
|
||||
timeRange: timeRanges.find(tr => tr.lower === 'now() - 1h'),
|
||||
dygraphs: [],
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ class HostPage extends Component {
|
|||
async fetchHostsAndMeasurements(layouts) {
|
||||
const {source, params} = this.props
|
||||
|
||||
const hosts = await getAllHosts(source.links.proxy, source.telegraf)
|
||||
const host = await getAppsForHost(
|
||||
source.links.proxy,
|
||||
params.hostID,
|
||||
|
@ -46,7 +45,7 @@ class HostPage extends Component {
|
|||
|
||||
const measurements = await getMeasurementsForHost(source, params.hostID)
|
||||
|
||||
return {host, hosts, measurements}
|
||||
return {host, measurements}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
|
@ -56,9 +55,7 @@ class HostPage extends Component {
|
|||
const {location} = this.props
|
||||
|
||||
// fetching layouts and mappings can be done at the same time
|
||||
const {hosts, host, measurements} = await this.fetchHostsAndMeasurements(
|
||||
layouts
|
||||
)
|
||||
const {host, measurements} = await this.fetchHostsAndMeasurements(layouts)
|
||||
|
||||
const focusedApp = location.query.app
|
||||
|
||||
|
@ -74,15 +71,9 @@ class HostPage extends Component {
|
|||
)
|
||||
})
|
||||
|
||||
// only display hosts in the list if they match the current app
|
||||
let filteredHosts = hosts
|
||||
if (focusedApp) {
|
||||
filteredHosts = _.pickBy(hosts, (val, __, ___) => {
|
||||
return _.get(val, 'apps', []).includes(focusedApp)
|
||||
})
|
||||
}
|
||||
const hostLinks = await this.getHostLinks()
|
||||
|
||||
this.setState({layouts: filteredLayouts, hosts: filteredHosts}) // eslint-disable-line react/no-did-mount-set-state
|
||||
this.setState({layouts: filteredLayouts, hostLinks}) // eslint-disable-line react/no-did-mount-set-state
|
||||
}
|
||||
|
||||
handleChooseTimeRange = ({lower, upper}) => {
|
||||
|
@ -173,7 +164,7 @@ class HostPage extends Component {
|
|||
handleChooseAutoRefresh,
|
||||
handleClickPresentationButton,
|
||||
} = this.props
|
||||
const {timeRange} = this.state
|
||||
const {timeRange, hostLinks} = this.state
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
|
@ -186,8 +177,7 @@ class HostPage extends Component {
|
|||
handleChooseAutoRefresh={handleChooseAutoRefresh}
|
||||
handleChooseTimeRange={this.handleChooseTimeRange}
|
||||
handleClickPresentationButton={handleClickPresentationButton}
|
||||
dashboardLinks={this.dashboardLinks}
|
||||
activeDashboardLink={this.activeDashboardLink}
|
||||
dashboardLinks={hostLinks}
|
||||
/>
|
||||
<FancyScrollbar
|
||||
className={classnames({
|
||||
|
@ -203,30 +193,16 @@ class HostPage extends Component {
|
|||
)
|
||||
}
|
||||
|
||||
get dashboardLinks() {
|
||||
const {
|
||||
params: {sourceID},
|
||||
} = this.props
|
||||
const {hosts} = this.state
|
||||
|
||||
if (!sourceID || !hosts) {
|
||||
return []
|
||||
}
|
||||
|
||||
return Object.values(hosts).map(({name}) => ({
|
||||
key: name,
|
||||
text: name,
|
||||
to: `/sources/${sourceID}/hosts/${name}`,
|
||||
}))
|
||||
}
|
||||
|
||||
get activeDashboardLink() {
|
||||
getHostLinks = async () => {
|
||||
const {
|
||||
source,
|
||||
params: {hostID},
|
||||
} = this.props
|
||||
const {dashboardLinks} = this
|
||||
|
||||
return dashboardLinks.find(d => d.key === hostID)
|
||||
const activeHost = {name: hostID}
|
||||
const links = await loadHostsLinks(source, {activeHost})
|
||||
|
||||
return links
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import {Source} from 'src/types/sources'
|
||||
import {HostNames, HostName} from 'src/types/hosts'
|
||||
import {DashboardSwitcherLinks} from 'src/types/dashboards'
|
||||
|
||||
export const EMPTY_LINKS = {
|
||||
links: [],
|
||||
active: null,
|
||||
}
|
||||
|
||||
export const linksFromHosts = (
|
||||
hostNames: HostNames,
|
||||
source: Source
|
||||
): DashboardSwitcherLinks => {
|
||||
const links = Object.values(hostNames).map(h => {
|
||||
return {
|
||||
key: h.name,
|
||||
text: h.name,
|
||||
to: `/sources/${source.id}/hosts/${h.name}`,
|
||||
}
|
||||
})
|
||||
|
||||
return {links, active: null}
|
||||
}
|
||||
|
||||
export const updateActiveHostLink = (
|
||||
hostLinks: DashboardSwitcherLinks,
|
||||
host: HostName
|
||||
): DashboardSwitcherLinks => {
|
||||
const active = hostLinks.links.find(link => link.key === host.name)
|
||||
|
||||
return {...hostLinks, active}
|
||||
}
|
|
@ -6,3 +6,7 @@ export interface DashboardsResponse {
|
|||
}
|
||||
|
||||
export type GetDashboards = () => Promise<AxiosResponse<DashboardsResponse>>
|
||||
export interface LoadLinksOptions {
|
||||
activeDashboard: Dashboard
|
||||
dashboardsAJAX?: GetDashboards
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export interface HostNames {
|
||||
[index: string]: HostName
|
||||
}
|
||||
|
||||
export interface HostName {
|
||||
name: string
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
import {loadDashboardLinks} from 'src/dashboards/apis'
|
||||
import {dashboard, source} from 'test/resources'
|
||||
|
||||
describe('dashboards.apis.loadDashboardLinks', () => {
|
||||
const socure = {...source, id: '897'}
|
||||
|
||||
const activeDashboard = {
|
||||
...dashboard,
|
||||
id: 9001,
|
||||
name: 'Low Dash',
|
||||
}
|
||||
|
||||
const dashboards = [
|
||||
{
|
||||
...dashboard,
|
||||
id: 123,
|
||||
name: 'Test Dashboard',
|
||||
},
|
||||
activeDashboard,
|
||||
{
|
||||
...dashboard,
|
||||
id: 2282,
|
||||
name: 'Sample Dash',
|
||||
},
|
||||
]
|
||||
|
||||
const data = {
|
||||
dashboards,
|
||||
}
|
||||
|
||||
const axiosResponse = {
|
||||
data,
|
||||
status: 200,
|
||||
statusText: 'Okay',
|
||||
headers: null,
|
||||
config: null,
|
||||
}
|
||||
|
||||
const getDashboards = async () => axiosResponse
|
||||
|
||||
const options = {
|
||||
activeDashboard,
|
||||
dashboardsAJAX: getDashboards,
|
||||
}
|
||||
|
||||
it('can load dashboard links for source', async () => {
|
||||
const actualLinks = await loadDashboardLinks(socure, options)
|
||||
|
||||
const expectedLinks = {
|
||||
links: [
|
||||
{
|
||||
key: '123',
|
||||
text: 'Test Dashboard',
|
||||
to: '/sources/897/dashboards/123',
|
||||
},
|
||||
{
|
||||
key: '9001',
|
||||
text: 'Low Dash',
|
||||
to: '/sources/897/dashboards/9001',
|
||||
},
|
||||
{
|
||||
key: '2282',
|
||||
text: 'Sample Dash',
|
||||
to: '/sources/897/dashboards/2282',
|
||||
},
|
||||
],
|
||||
active: {
|
||||
key: '9001',
|
||||
text: 'Low Dash',
|
||||
to: '/sources/897/dashboards/9001',
|
||||
},
|
||||
}
|
||||
|
||||
expect(actualLinks).toEqual(expectedLinks)
|
||||
})
|
||||
})
|
|
@ -1,11 +1,11 @@
|
|||
import {
|
||||
loadDashboardLinks,
|
||||
linksFromDashboards,
|
||||
updateActiveDashboardLink,
|
||||
} from 'src/dashboards/utils/dashboardSwitcherLinks'
|
||||
import {dashboard, source} from 'test/resources'
|
||||
|
||||
describe('dashboards.utils.dashboardSwitcherLinks', () => {
|
||||
describe('loadDashboardLinks', () => {
|
||||
describe('linksFromDashboards', () => {
|
||||
const socure = {...source, id: '897'}
|
||||
|
||||
const dashboards = [
|
||||
|
@ -16,22 +16,8 @@ describe('dashboards.utils.dashboardSwitcherLinks', () => {
|
|||
},
|
||||
]
|
||||
|
||||
const data = {
|
||||
dashboards,
|
||||
}
|
||||
|
||||
const axiosResponse = {
|
||||
data,
|
||||
status: 200,
|
||||
statusText: 'Okay',
|
||||
headers: null,
|
||||
config: null,
|
||||
}
|
||||
|
||||
const getDashboards = async () => axiosResponse
|
||||
|
||||
it('can load dashboard links for source', async () => {
|
||||
const actualLinks = await loadDashboardLinks(socure, getDashboards)
|
||||
it('can build dashboard links for source', () => {
|
||||
const actualLinks = linksFromDashboards(dashboards, socure)
|
||||
|
||||
const expectedLinks = {
|
||||
links: [
|
|
@ -0,0 +1,61 @@
|
|||
import {loadHostsLinks} from 'src/hosts/apis'
|
||||
import {source} from 'test/resources'
|
||||
|
||||
import {HostNames} from 'src/types/hosts'
|
||||
import {DashboardSwitcherLinks} from 'src/types/dashboards'
|
||||
|
||||
describe('hosts.apis.loadHostLinks', () => {
|
||||
const socure = {...source, id: '897'}
|
||||
|
||||
const hostNames: HostNames = {
|
||||
'zelda.local': {
|
||||
name: 'zelda.local',
|
||||
},
|
||||
'gannon.local': {
|
||||
name: 'gannon.local',
|
||||
},
|
||||
'korok.local': {
|
||||
name: 'korok.local',
|
||||
},
|
||||
}
|
||||
|
||||
const hostNamesAJAX = async () => hostNames
|
||||
|
||||
const options = {
|
||||
activeHost: {
|
||||
name: 'korok.local',
|
||||
},
|
||||
getHostNamesAJAX: hostNamesAJAX,
|
||||
}
|
||||
|
||||
it('can load the host links', async () => {
|
||||
const hostLinks = await loadHostsLinks(socure, options)
|
||||
|
||||
const expectedLinks: DashboardSwitcherLinks = {
|
||||
active: {
|
||||
key: 'korok.local',
|
||||
text: 'korok.local',
|
||||
to: '/sources/897/hosts/korok.local',
|
||||
},
|
||||
links: [
|
||||
{
|
||||
key: 'zelda.local',
|
||||
text: 'zelda.local',
|
||||
to: '/sources/897/hosts/zelda.local',
|
||||
},
|
||||
{
|
||||
key: 'gannon.local',
|
||||
text: 'gannon.local',
|
||||
to: '/sources/897/hosts/gannon.local',
|
||||
},
|
||||
{
|
||||
key: 'korok.local',
|
||||
text: 'korok.local',
|
||||
to: '/sources/897/hosts/korok.local',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
expect(hostLinks).toEqual(expectedLinks)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,80 @@
|
|||
import {
|
||||
updateActiveHostLink,
|
||||
linksFromHosts,
|
||||
} from 'src/hosts/utils/hostsSwitcherLinks'
|
||||
import {source} from 'test/resources'
|
||||
import {HostNames} from 'src/types/hosts'
|
||||
|
||||
describe('hosts.utils.hostSwitcherLinks', () => {
|
||||
describe('linksFromHosts', () => {
|
||||
const socure = {...source, id: '897'}
|
||||
|
||||
const hostNames: HostNames = {
|
||||
'zelda.local': {
|
||||
name: 'zelda.local',
|
||||
},
|
||||
'gannon.local': {
|
||||
name: 'gannon.local',
|
||||
},
|
||||
}
|
||||
|
||||
it('can build host links for a given source', () => {
|
||||
const actualLinks = linksFromHosts(hostNames, socure)
|
||||
|
||||
const expectedLinks = {
|
||||
links: [
|
||||
{
|
||||
key: 'zelda.local',
|
||||
text: 'zelda.local',
|
||||
to: '/sources/897/hosts/zelda.local',
|
||||
},
|
||||
{
|
||||
key: 'gannon.local',
|
||||
text: 'gannon.local',
|
||||
to: '/sources/897/hosts/gannon.local',
|
||||
},
|
||||
],
|
||||
active: null,
|
||||
}
|
||||
|
||||
expect(actualLinks).toEqual(expectedLinks)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateActiveHostLink', () => {
|
||||
const link1 = {
|
||||
key: 'korok.local',
|
||||
text: 'korok.local',
|
||||
to: '/sources/897/hosts/korok.local',
|
||||
}
|
||||
|
||||
const link2 = {
|
||||
key: 'deku.local',
|
||||
text: 'deku.local',
|
||||
to: '/sources/897/hosts/deku.local',
|
||||
}
|
||||
|
||||
const activeLink = {
|
||||
key: 'robbie.local',
|
||||
text: 'robbie.local',
|
||||
to: '/sources/897/hosts/robbie.local',
|
||||
}
|
||||
|
||||
const activeHostName = {
|
||||
name: 'robbie.local',
|
||||
}
|
||||
|
||||
const links = [link1, activeLink, link2]
|
||||
|
||||
it('can set the active host link', () => {
|
||||
const loadedLinks = {
|
||||
links,
|
||||
active: null,
|
||||
}
|
||||
const actualLinks = updateActiveHostLink(loadedLinks, activeHostName)
|
||||
const expectedLinks = {links, active: activeLink}
|
||||
|
||||
expect(actualLinks).toEqual(expectedLinks)
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue