Add util for loading DashboardLinks

pull/3828/head
Delmer Reed 2018-07-05 18:17:55 -04:00
parent e81180742b
commit 75c123323b
9 changed files with 199 additions and 70 deletions

View File

@ -47,7 +47,6 @@ import idNormalizer, {TYPE_ID} from 'src/normalizers/id'
import {defaultTimeRange} from 'src/shared/data/timeRanges'
// Types
import {AxiosResponse} from 'axios'
import {
Dashboard,
Cell,
@ -58,7 +57,6 @@ import {
TemplateValue,
TemplateType,
} from 'src/types'
import * as DashboardsApis from 'src/types/apis/dashboards'
export enum ActionType {
LoadDashboards = 'LOAD_DASHBOARDS',
@ -401,9 +399,7 @@ export const getDashboardsAsync = () => async (
try {
const {
data: {dashboards},
} = (await getDashboardsAJAX()) as AxiosResponse<
DashboardsApis.DashboardsResponse
>
} = await getDashboardsAJAX()
dispatch(loadDashboards(dashboards))
return dashboards
} catch (error) {
@ -584,9 +580,8 @@ export const importDashboardAsync = (dashboard: Dashboard) => async (
const {
data: {dashboards},
} = (await getDashboardsAJAX()) as AxiosResponse<
DashboardsApis.DashboardsResponse
>
} = await getDashboardsAJAX()
dispatch(loadDashboards(dashboards))
dispatch(notify(notifyDashboardImported(name)))

View File

@ -1,15 +1,13 @@
import AJAX from 'src/utils/ajax'
import {AxiosResponse} from 'axios'
import {DashboardsResponse} from 'src/types/apis/dashboards'
import {DashboardsResponse, GetDashboards} from 'src/types/apis/dashboards'
export const getDashboards = (): Promise<
AxiosResponse<DashboardsResponse> | DashboardsResponse
> => {
return AJAX({
export const getDashboards: GetDashboards = () => {
return AJAX<DashboardsResponse>({
method: 'GET',
resource: 'dashboards',
})
}) as Promise<AxiosResponse<DashboardsResponse>>
}
export const getDashboard = async dashboardID => {

View File

@ -32,8 +32,7 @@ interface Props {
zoomedTimeRange: QueriesModels.TimeRange
onCancel: () => void
onSave: (name: string) => Promise<void>
dashboardLinks: DashboardsModels.DashboardSwitcherLink[]
activeDashboardLink?: DashboardsModels.DashboardSwitcherLink
dashboardLinks: DashboardsModels.DashboardSwitcherLinks
isHidden: boolean
}
@ -146,15 +145,10 @@ class DashboardHeader extends Component<Props> {
}
private get dashboardSwitcher(): JSX.Element {
const {dashboardLinks, activeDashboardLink} = this.props
const {dashboardLinks} = this.props
if (dashboardLinks.length > 1) {
return (
<DashboardSwitcher
links={dashboardLinks}
activeLink={activeDashboardLink}
/>
)
if (dashboardLinks.links.length > 1) {
return <DashboardSwitcher dashboardLinks={dashboardLinks} />
}
}

View File

@ -1,6 +1,7 @@
import React, {PureComponent} from 'react'
import {Link} from 'react-router'
import _ from 'lodash'
import classnames from 'classnames'
import OnClickOutside from 'src/shared/components/OnClickOutside'
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
@ -8,12 +9,13 @@ import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {DROPDOWN_MENU_MAX_HEIGHT} from 'src/shared/constants/index'
import {DashboardSwitcherLink} from 'src/types/dashboards'
import {
DashboardSwitcherLinks,
DashboardSwitcherLink,
} from 'src/types/dashboards'
interface Props {
links: DashboardSwitcherLink[]
activeLink?: DashboardSwitcherLink
dashboardLinks: DashboardSwitcherLinks
}
interface State {
@ -66,17 +68,14 @@ class DashboardSwitcher extends PureComponent<Props, State> {
}
private get links(): JSX.Element[] {
const {links, activeLink} = this.props
return _.sortBy(links, ['text', 'key']).map(link => {
let activeClass = ''
if (activeLink && link.key === activeLink.key) {
activeClass = 'active'
}
return _.sortBy(this.dashLinks, ['text', 'key']).map(link => {
return (
<li key={link.key} className={`dropdown-item ${activeClass}`}>
<li
key={link.key}
className={classnames('dropdown-item', {
active: link === this.activeLink,
})}
>
<Link to={link.to} onClick={this.handleCloseMenu}>
{link.text}
</Link>
@ -84,6 +83,14 @@ class DashboardSwitcher extends PureComponent<Props, State> {
)
})
}
private get activeLink(): DashboardSwitcherLink {
return this.props.dashboardLinks.active
}
private get dashLinks(): DashboardSwitcherLink[] {
return this.props.dashboardLinks.links
}
}
export default OnClickOutside(DashboardSwitcher)

View File

@ -24,7 +24,7 @@ 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 {getDashboards as getDashboardsAJAX} from 'src/dashboards/apis'
import * as dashboardSwitcher from 'src/dashboards/utils/dashboardSwitcherLinks'
// Constants
import {
@ -40,8 +40,6 @@ import {WithRouterProps} from 'react-router'
import {ManualRefreshProps} from 'src/shared/components/ManualRefresh'
import {Location} from 'history'
import {InjectedRouter} from 'react-router'
import {AxiosResponse} from 'axios'
import {DashboardsResponse} from 'src/types/apis/dashboards'
import * as AnnotationsActions from 'src/types/actions/annotations'
import * as AppActions from 'src/types/actions/app'
import * as ColorsModels from 'src/types/colors'
@ -112,7 +110,7 @@ interface State {
selectedCell: DashboardsModels.Cell | null
scrollTop: number
windowHeight: number
dashboardLinks: DashboardsModels.DashboardSwitcherLink[]
dashboardLinks: DashboardsModels.DashboardSwitcherLinks
}
@ErrorHandling
@ -127,7 +125,7 @@ class DashboardPage extends Component<Props, State> {
selectedCell: null,
scrollTop: 0,
windowHeight: window.innerHeight,
dashboardLinks: [],
dashboardLinks: dashboardSwitcher.EMPTY_LINKS,
}
}
@ -290,7 +288,6 @@ class DashboardPage extends Component<Props, State> {
onCancel={this.handleCancelEditDashboard}
onEditDashboard={this.handleEditDashboard}
dashboardLinks={dashboardLinks}
activeDashboardLink={this.activeDashboardLink}
activeDashboard={dashboard ? dashboard.name : ''}
showTemplateControlBar={showTemplateControlBar}
handleChooseAutoRefresh={handleChooseAutoRefresh}
@ -487,38 +484,22 @@ class DashboardPage extends Component<Props, State> {
}
private getDashboardLinks = async (): Promise<void> => {
const {source} = this.props
const {source, dashboard} = this.props
try {
const resp = (await getDashboardsAJAX()) as AxiosResponse<
DashboardsResponse
>
const dashboards = resp.data.dashboards
const dashboardLinks = dashboards.map(d => {
return {
key: String(d.id),
text: d.name,
to: `/sources/${source.id}/dashboards/${d.id}`,
}
})
const links = await dashboardSwitcher.loadDashboardLinks(source)
const dashboardLinks = dashboardSwitcher.updateActiveDashboardLink(
links,
dashboard
)
this.setState({dashboardLinks})
this.setState({
dashboardLinks,
})
} catch (error) {
console.error(error)
}
}
private get activeDashboardLink(): DashboardsModels.DashboardSwitcherLink | null {
const {dashboard} = this.props
if (!dashboard) {
return null
}
const {dashboardLinks} = this.state
return dashboardLinks.find(link => link.key === String(dashboard.id))
}
}
const mstp = (state, {params: {dashboardID}}) => {
@ -560,7 +541,6 @@ const mstp = (state, {params: {dashboardID}}) => {
dashboardID: Number(dashboardID),
timeRange,
zoomedTimeRange,
dashboards,
autoRefresh,
isUsingAuth,
cellQueryStatus,

View File

@ -0,0 +1,51 @@
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'
export const EMPTY_LINKS = {
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 = (
dashboards: Dashboard[],
source: Source
): DashboardSwitcherLinks => {
const links = dashboards.map(d => {
return {
key: String(d.id),
text: d.name,
to: `/sources/${source.id}/dashboards/${d.id}`,
}
})
return {links, active: null}
}
export const updateActiveDashboardLink = (
dashboardLinks: DashboardSwitcherLinks,
dashboard: Dashboard
) => {
if (!dashboard) {
return {...dashboardLinks, active: null}
}
const active = dashboardLinks.links.find(
link => link.key === String(dashboard.id)
)
return {...dashboardLinks, active}
}

View File

@ -1,5 +1,8 @@
import {Dashboard} from 'src/types/dashboards'
import {AxiosResponse} from 'axios'
export interface DashboardsResponse {
dashboards: Dashboard[]
}
export type GetDashboards = () => Promise<AxiosResponse<DashboardsResponse>>

View File

@ -151,3 +151,8 @@ export interface DashboardUIState {
hoverTime: string
activeCellID: string
}
export interface DashboardSwitcherLinks {
active?: DashboardSwitcherLink
links: DashboardSwitcherLink[]
}

View File

@ -0,0 +1,96 @@
import {
loadDashboardLinks,
updateActiveDashboardLink,
} from 'src/dashboards/utils/dashboardSwitcherLinks'
import {dashboard, source} from 'test/resources'
describe('dashboards.utils.dashboardSwitcherLinks', () => {
describe('loadDashboardLinks', () => {
const socure = {...source, id: '897'}
const dashboards = [
{
...dashboard,
id: 123,
name: 'Test Dashboard',
},
]
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)
const expectedLinks = {
links: [
{
key: '123',
text: 'Test Dashboard',
to: '/sources/897/dashboards/123',
},
],
active: null,
}
expect(actualLinks).toEqual(expectedLinks)
})
})
describe('updateActiveDashboardLink', () => {
const activeDashboard = {
...dashboard,
id: 123,
name: 'Test Dashboard',
}
const activeLink = {
key: '123',
text: 'Test Dashboard',
to: '/sources/897/dashboards/123',
}
const link1 = {
key: '9001',
text: 'Low Dash',
to: '/sources/897/dashboards/9001',
}
const link2 = {
key: '2282',
text: 'Low Dash',
to: '/sources/897/dashboards/2282',
}
const links = [link1, activeLink, link2]
it('can set the active link', () => {
const loadedLinks = {links, active: null}
const actualLinks = updateActiveDashboardLink(
loadedLinks,
activeDashboard
)
const expectedLinks = {links, active: activeLink}
expect(actualLinks).toEqual(expectedLinks)
})
it('can handle a missing dashboard', () => {
const loadedLinks = {links, active: null}
const actualLinks = updateActiveDashboardLink(loadedLinks, undefined)
const expectedLinks = {links, active: null}
expect(actualLinks).toEqual(expectedLinks)
})
})
})