Add asset limits getter to DashboardsIndex

pull/13588/head
Deniz Kusefoglu 2019-04-23 14:05:07 -07:00
parent 20ac4f2357
commit fbdc65b98d
4 changed files with 134 additions and 77 deletions

View File

@ -23,10 +23,6 @@ import {
updateTimeRangeFromQueryParams,
DeleteTimeRangeAction,
} from 'src/dashboards/actions/ranges'
import {
importDashboardSucceeded,
importDashboardFailed,
} from 'src/shared/copy/notifications'
import {setView, SetViewAction, setViews} from 'src/dashboards/actions/views'
import {
getVariables,
@ -34,6 +30,7 @@ import {
selectValue,
} from 'src/variables/actions'
import {setExportTemplate} from 'src/templates/actions'
import {checkDashboardLimits} from 'src/cloud/actions/limits'
// Utils
import {filterUnusedVars} from 'src/shared/utils/filterUnusedVars'
@ -246,14 +243,15 @@ export const createDashboardFromTemplate = (
const dashboards = await getDashboardsAJAX(org.id)
dispatch(setDashboards(RemoteDataState.Done, dashboards))
dispatch(notify(importDashboardSucceeded()))
dispatch(notify(copy.importDashboardSucceeded()))
dispatch(checkDashboardLimits())
} catch (error) {
dispatch(notify(importDashboardFailed(error)))
dispatch(notify(copy.importDashboardFailed(error)))
}
}
export const deleteDashboardAsync = (dashboard: Dashboard) => async (
dispatch: Dispatch<Action>
dispatch
): Promise<void> => {
dispatch(removeDashboard(dashboard.id))
dispatch(deleteTimeRange(dashboard.id))
@ -261,6 +259,7 @@ export const deleteDashboardAsync = (dashboard: Dashboard) => async (
try {
await deleteDashboardAJAX(dashboard)
dispatch(notify(copy.dashboardDeleted(dashboard.name)))
dispatch(checkDashboardLimits())
} catch (error) {
dispatch(
notify(copy.dashboardDeleteFailed(dashboard.name, error.data.message))

View File

@ -3,47 +3,48 @@ import React, {PureComponent} from 'react'
import {InjectedRouter} from 'react-router'
import {connect} from 'react-redux'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
// Components
import DashboardsIndexContents from 'src/dashboards/components/dashboard_index/DashboardsIndexContents'
import {Page} from 'src/pageLayout'
import SearchWidget from 'src/shared/components/search_widget/SearchWidget'
import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
import PageTitleWithOrg from 'src/shared/components/PageTitleWithOrg'
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
import GetResources, {ResourceTypes} from 'src/shared/components/GetResources'
// APIs
import {createDashboard, cloneDashboard} from 'src/dashboards/apis/'
// Actions
import {
getDashboardsAsync,
deleteDashboardAsync,
updateDashboardAsync,
} from 'src/dashboards/actions'
import {retainRangesDashTimeV1 as retainRangesDashTimeV1Action} from 'src/dashboards/actions/ranges'
import {notify as notifyAction} from 'src/shared/actions/notifications'
import GetResources, {ResourceTypes} from 'src/shared/components/GetResources'
import {checkDashboardLimits as checkDashboardLimitsAction} from 'src/cloud/actions/limits'
// Constants
import {DEFAULT_DASHBOARD_NAME} from 'src/dashboards/constants/index'
import {dashboardCreateFailed} from 'src/shared/copy/notifications'
// Types
import {Notification} from 'src/types/notifications'
import {Dashboard, AppState} from 'src/types'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {LimitStatus} from 'src/cloud/actions/limits'
import {ComponentStatus} from 'src/clockface'
interface DispatchProps {
handleGetDashboards: typeof getDashboardsAsync
handleDeleteDashboard: typeof deleteDashboardAsync
handleUpdateDashboard: typeof updateDashboardAsync
notify: (message: Notification) => void
retainRangesDashTimeV1: (dashboardIDs: string[]) => void
checkDashboardLimits: typeof checkDashboardLimitsAction
notify: typeof notifyAction
}
interface StateProps {
dashboards: Dashboard[]
limitStatus: LimitStatus
}
interface OwnProps {
@ -67,15 +68,8 @@ class DashboardIndex extends PureComponent<Props, State> {
}
}
public async componentDidMount() {
const {dashboards} = this.props
const dashboardIDs = dashboards.map(d => d.id)
this.props.retainRangesDashTimeV1(dashboardIDs)
}
public render() {
const {dashboards, notify, handleUpdateDashboard} = this.props
const {handleUpdateDashboard, handleDeleteDashboard} = this.props
const {searchTerm} = this.state
return (
@ -92,30 +86,33 @@ class DashboardIndex extends PureComponent<Props, State> {
onSelectTemplate={this.summonImportFromTemplateOverlay}
resourceName="Dashboard"
canImportFromTemplate={true}
status={this.addResourceStatus}
/>
</Page.Header.Right>
</Page.Header>
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-md-12">
<GetResources resource={ResourceTypes.Dashboards}>
<DashboardsIndexContents
filterComponent={() => (
<SearchWidget
placeholderText="Filter dashboards..."
onSearch={this.handleFilterDashboards}
<GetResources resource={ResourceTypes.Labels}>
<GetAssetLimits>
<DashboardsIndexContents
filterComponent={() => (
<SearchWidget
placeholderText="Filter dashboards..."
onSearch={this.handleFilterDashboards}
searchTerm={searchTerm}
/>
)}
onDeleteDashboard={handleDeleteDashboard}
onCreateDashboard={this.handleCreateDashboard}
onCloneDashboard={this.handleCloneDashboard}
onUpdateDashboard={handleUpdateDashboard}
searchTerm={searchTerm}
onFilterChange={this.handleFilterDashboards}
onImportDashboard={this.summonImportOverlay}
/>
)}
dashboards={dashboards}
onDeleteDashboard={this.handleDeleteDashboard}
onCreateDashboard={this.handleCreateDashboard}
onCloneDashboard={this.handleCloneDashboard}
onUpdateDashboard={handleUpdateDashboard}
notify={notify}
searchTerm={searchTerm}
onFilterChange={this.handleFilterDashboards}
onImportDashboard={this.summonImportOverlay}
/>
</GetAssetLimits>
</GetResources>
</GetResources>
</div>
</Page.Contents>
@ -130,6 +127,7 @@ class DashboardIndex extends PureComponent<Props, State> {
router,
notify,
params: {orgID},
checkDashboardLimits,
} = this.props
try {
const newDashboard = {
@ -138,6 +136,7 @@ class DashboardIndex extends PureComponent<Props, State> {
orgID,
}
const data = await createDashboard(newDashboard)
checkDashboardLimits()
router.push(`/orgs/${orgID}/dashboards/${data.id}`)
} catch (error) {
notify(dashboardCreateFailed())
@ -152,6 +151,7 @@ class DashboardIndex extends PureComponent<Props, State> {
notify,
dashboards,
params: {orgID},
checkDashboardLimits,
} = this.props
try {
const data = await cloneDashboard(
@ -163,16 +163,13 @@ class DashboardIndex extends PureComponent<Props, State> {
orgID
)
router.push(`/orgs/${orgID}/dashboards/${data.id}`)
checkDashboardLimits()
} catch (error) {
console.error(error)
notify(dashboardCreateFailed())
}
}
private handleDeleteDashboard = (dashboard: Dashboard) => {
this.props.handleDeleteDashboard(dashboard)
}
private handleFilterDashboards = (searchTerm: string): void => {
this.setState({searchTerm})
}
@ -192,24 +189,38 @@ class DashboardIndex extends PureComponent<Props, State> {
} = this.props
router.push(`/orgs/${orgID}/dashboards/import/template`)
}
private get addResourceStatus(): ComponentStatus {
const {limitStatus} = this.props
if (limitStatus === LimitStatus.EXCEEDED) {
return ComponentStatus.Disabled
} else {
return ComponentStatus.Default
}
}
}
const mstp = (state: AppState): StateProps => {
const {
dashboards: {list: dashboards},
cloud: {
limits: {
dashboards: {limitStatus},
},
},
} = state
return {
dashboards,
limitStatus,
}
}
const mdtp: DispatchProps = {
notify: notifyAction,
handleGetDashboards: getDashboardsAsync,
handleDeleteDashboard: deleteDashboardAsync,
handleUpdateDashboard: updateDashboardAsync,
retainRangesDashTimeV1: retainRangesDashTimeV1Action,
checkDashboardLimits: checkDashboardLimitsAction,
}
export default connect<StateProps, DispatchProps, OwnProps>(

View File

@ -1,34 +1,55 @@
// Libraries
import React, {Component} from 'react'
import {connect} from 'react-redux'
import _ from 'lodash'
// Components
import Table from 'src/dashboards/components/dashboard_index/Table'
import FilterList from 'src/shared/components/Filter'
import GetResources, {ResourceTypes} from 'src/shared/components/GetResources'
// Actions
import {retainRangesDashTimeV1 as retainRangesDashTimeV1Action} from 'src/dashboards/actions/ranges'
import {checkDashboardLimits as checkDashboardLimitsAction} from 'src/cloud/actions/limits'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
// Types
import {Dashboard} from 'src/types'
import {Notification} from 'src/types/notifications'
import {Dashboard, AppState, RemoteDataState} from 'src/types'
interface Props {
dashboards: Dashboard[]
interface OwnProps {
onCreateDashboard: () => void
onCloneDashboard: (dashboard: Dashboard) => void
onDeleteDashboard: (dashboard: Dashboard) => void
onUpdateDashboard: (dashboard: Dashboard) => void
onFilterChange: (searchTerm: string) => void
notify: (message: Notification) => void
searchTerm: string
filterComponent?: () => JSX.Element
onImportDashboard: () => void
}
interface DispatchProps {
retainRangesDashTimeV1: typeof retainRangesDashTimeV1Action
checkDashboardLimits: typeof checkDashboardLimitsAction
}
interface StateProps {
dashboards: Dashboard[]
limitStatus: RemoteDataState
}
type Props = DispatchProps & StateProps & OwnProps
@ErrorHandling
export default class DashboardsIndexContents extends Component<Props> {
class DashboardsIndexContents extends Component<Props> {
public async componentDidMount() {
const {dashboards} = this.props
const dashboardIDs = dashboards.map(d => d.id)
this.props.retainRangesDashTimeV1(dashboardIDs)
this.props.checkDashboardLimits()
}
public render() {
const {
onDeleteDashboard,
@ -43,28 +64,50 @@ export default class DashboardsIndexContents extends Component<Props> {
} = this.props
return (
<GetResources resource={ResourceTypes.Labels}>
<FilterList<Dashboard>
list={dashboards}
searchTerm={searchTerm}
searchKeys={['name', 'labels[].name']}
sortByKey="name"
>
{filteredDashboards => (
<Table
searchTerm={searchTerm}
filterComponent={filterComponent}
dashboards={filteredDashboards}
onDeleteDashboard={onDeleteDashboard}
onCreateDashboard={onCreateDashboard}
onCloneDashboard={onCloneDashboard}
onUpdateDashboard={onUpdateDashboard}
onFilterChange={onFilterChange}
onImportDashboard={onImportDashboard}
/>
)}
</FilterList>
</GetResources>
<FilterList<Dashboard>
list={dashboards}
searchTerm={searchTerm}
searchKeys={['name', 'labels[].name']}
sortByKey="name"
>
{filteredDashboards => (
<Table
searchTerm={searchTerm}
filterComponent={filterComponent}
dashboards={filteredDashboards}
onDeleteDashboard={onDeleteDashboard}
onCreateDashboard={onCreateDashboard}
onCloneDashboard={onCloneDashboard}
onUpdateDashboard={onUpdateDashboard}
onFilterChange={onFilterChange}
onImportDashboard={onImportDashboard}
/>
)}
</FilterList>
)
}
}
const mstp = (state: AppState): StateProps => {
const {
dashboards: {list: dashboards},
cloud: {
limits: {status},
},
} = state
return {
dashboards,
limitStatus: status,
}
}
const mdtp: DispatchProps = {
retainRangesDashTimeV1: retainRangesDashTimeV1Action,
checkDashboardLimits: checkDashboardLimitsAction,
}
export default connect<StateProps, DispatchProps, OwnProps>(
mstp,
mdtp
)(DashboardsIndexContents)

View File

@ -3,7 +3,7 @@ import React, {PureComponent} from 'react'
import _ from 'lodash'
// Components
import {Dropdown, DropdownMode} from 'src/clockface'
import {Dropdown, DropdownMode, ComponentStatus} from 'src/clockface'
// Types
import {IconFont, ComponentColor, ComponentSize} from '@influxdata/clockface'
@ -14,10 +14,12 @@ interface OwnProps {
onSelectTemplate?: () => void
resourceName: string
canImportFromTemplate?: boolean
status?: ComponentStatus
}
interface DefaultProps {
canImportFromTemplate: boolean
status: ComponentStatus
}
type Props = OwnProps & DefaultProps
@ -25,6 +27,7 @@ type Props = OwnProps & DefaultProps
export default class AddResourceDropdown extends PureComponent<Props> {
public static defaultProps: DefaultProps = {
canImportFromTemplate: false,
status: ComponentStatus.Default,
}
public render() {
@ -37,6 +40,7 @@ export default class AddResourceDropdown extends PureComponent<Props> {
buttonSize={ComponentSize.Small}
widthPixels={160}
onChange={this.handleSelect}
status={this.props.status}
>
{this.optionItems}
</Dropdown>