Add clone dashboard functionality to orgs dashboard list (#11265)
Co-Authored-By: Deniz Kusefoglu <deniz@influxdata.com>pull/11259/head
parent
a2435354bb
commit
be430667a7
|
@ -13,6 +13,7 @@ import {
|
|||
ConfirmationButton,
|
||||
Stack,
|
||||
Label,
|
||||
ComponentColor,
|
||||
} from 'src/clockface'
|
||||
import EditableDescription from 'src/shared/components/editable_description/EditableDescription'
|
||||
|
||||
|
@ -72,6 +73,7 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
|
|||
<ComponentSpacer align={Alignment.Left} stackChildren={Stack.Columns}>
|
||||
<Button
|
||||
size={ComponentSize.ExtraSmall}
|
||||
color={ComponentColor.Secondary}
|
||||
text="Clone"
|
||||
icon={IconFont.Duplicate}
|
||||
onClick={this.handleClone}
|
||||
|
|
|
@ -1,26 +1,51 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import {IndexList} from 'src/clockface'
|
||||
import DashboardRow from 'src/organizations/components/DashboardRow'
|
||||
|
||||
// APIs
|
||||
import {createDashboard} from 'src/dashboards/apis/v2'
|
||||
|
||||
// Constants
|
||||
import {dashboardCreateFailed} from 'src/shared/copy/notifications'
|
||||
|
||||
// Actions
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
|
||||
// Types
|
||||
import {Notification} from 'src/types/notifications'
|
||||
import {Dashboard} from 'src/types/v2'
|
||||
|
||||
interface Props {
|
||||
// Decorators
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface DispatchProps {
|
||||
notify: (message: Notification) => void
|
||||
}
|
||||
|
||||
interface OwnProps {
|
||||
router: InjectedRouter
|
||||
orgID: string
|
||||
dashboards: Dashboard[]
|
||||
emptyState: JSX.Element
|
||||
onDeleteDashboard: (dashboard: Dashboard) => void
|
||||
}
|
||||
|
||||
export default class DashboardList extends PureComponent<Props> {
|
||||
type Props = DispatchProps & OwnProps
|
||||
|
||||
@ErrorHandling
|
||||
class DashboardList extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<IndexList>
|
||||
<IndexList.Header>
|
||||
<IndexList.HeaderCell columnName="name" width="50%" />
|
||||
<IndexList.HeaderCell columnName="modified" width="50%" />
|
||||
<IndexList.HeaderCell columnName="Name" width="50%" />
|
||||
<IndexList.HeaderCell columnName="Modified" width="25%" />
|
||||
<IndexList.HeaderCell columnName="" width="25%" />
|
||||
</IndexList.Header>
|
||||
<IndexList.Body columnCount={2} emptyState={this.props.emptyState}>
|
||||
{this.rows}
|
||||
|
@ -29,6 +54,24 @@ export default class DashboardList extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
|
||||
private handleCloneDashboard = async (
|
||||
dashboard: Dashboard
|
||||
): Promise<void> => {
|
||||
const {router, notify, orgID} = this.props
|
||||
const name = `${dashboard.name} (clone)`
|
||||
try {
|
||||
const data = await createDashboard({
|
||||
...dashboard,
|
||||
name,
|
||||
orgID,
|
||||
})
|
||||
|
||||
router.push(`/dashboards/${data.id}`)
|
||||
} catch (error) {
|
||||
notify(dashboardCreateFailed())
|
||||
}
|
||||
}
|
||||
|
||||
private get rows(): JSX.Element[] {
|
||||
const {onDeleteDashboard} = this.props
|
||||
|
||||
|
@ -37,7 +80,17 @@ export default class DashboardList extends PureComponent<Props> {
|
|||
dashboard={d}
|
||||
key={d.id}
|
||||
onDeleteDashboard={onDeleteDashboard}
|
||||
onCloneDashboard={this.handleCloneDashboard}
|
||||
/>
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
notify: notifyAction,
|
||||
}
|
||||
|
||||
export default connect<null, DispatchProps, OwnProps>(
|
||||
null,
|
||||
mdtp
|
||||
)(DashboardList)
|
||||
|
|
|
@ -4,8 +4,17 @@ import {Link} from 'react-router'
|
|||
import moment from 'moment'
|
||||
|
||||
// Components
|
||||
import {IndexList, Alignment, ComponentSize} from 'src/clockface'
|
||||
import ConfirmationButton from 'src/clockface/components/confirmation_button/ConfirmationButton'
|
||||
import {
|
||||
IndexList,
|
||||
Alignment,
|
||||
ComponentSize,
|
||||
ConfirmationButton,
|
||||
ComponentSpacer,
|
||||
Stack,
|
||||
Button,
|
||||
IconFont,
|
||||
ComponentColor,
|
||||
} from 'src/clockface'
|
||||
|
||||
// Types
|
||||
import {Dashboard} from 'src/types/v2'
|
||||
|
@ -16,6 +25,7 @@ import {UPDATED_AT_TIME_FORMAT} from 'src/dashboards/constants'
|
|||
interface Props {
|
||||
dashboard: Dashboard
|
||||
onDeleteDashboard: (dashboard: Dashboard) => void
|
||||
onCloneDashboard: (dashboard: Dashboard) => void
|
||||
}
|
||||
|
||||
export default class DashboardRow extends PureComponent<Props> {
|
||||
|
@ -27,19 +37,48 @@ export default class DashboardRow extends PureComponent<Props> {
|
|||
<IndexList.Cell>
|
||||
<Link to={`/dashboards/${dashboard.id}`}>{dashboard.name}</Link>
|
||||
</IndexList.Cell>
|
||||
<IndexList.Cell revealOnHover={true}>
|
||||
{moment(dashboard.meta.updatedAt).format(UPDATED_AT_TIME_FORMAT)}
|
||||
</IndexList.Cell>
|
||||
{this.lastModifiedCell}
|
||||
<IndexList.Cell revealOnHover={true} alignment={Alignment.Right}>
|
||||
<ConfirmationButton
|
||||
size={ComponentSize.ExtraSmall}
|
||||
text="Delete"
|
||||
confirmText="Confirm"
|
||||
onConfirm={onDeleteDashboard}
|
||||
returnValue={dashboard}
|
||||
/>
|
||||
<ComponentSpacer stackChildren={Stack.Columns} align={Alignment.Left}>
|
||||
<Button
|
||||
size={ComponentSize.ExtraSmall}
|
||||
color={ComponentColor.Secondary}
|
||||
text="Clone"
|
||||
icon={IconFont.Duplicate}
|
||||
titleText="Create a duplicate copy of this Dashboard"
|
||||
onClick={this.handleCloneDashboard}
|
||||
/>
|
||||
<ConfirmationButton
|
||||
size={ComponentSize.ExtraSmall}
|
||||
text="Delete"
|
||||
confirmText="Confirm"
|
||||
onConfirm={onDeleteDashboard}
|
||||
returnValue={dashboard}
|
||||
/>
|
||||
</ComponentSpacer>
|
||||
</IndexList.Cell>
|
||||
</IndexList.Row>
|
||||
)
|
||||
}
|
||||
|
||||
private handleCloneDashboard = (): void => {
|
||||
const {dashboard, onCloneDashboard} = this.props
|
||||
|
||||
onCloneDashboard(dashboard)
|
||||
}
|
||||
|
||||
private get lastModifiedCell(): JSX.Element {
|
||||
const {dashboard} = this.props
|
||||
|
||||
const relativeTimestamp = moment(dashboard.meta.updatedAt).fromNow()
|
||||
const absoluteTimestamp = moment(dashboard.meta.updatedAt).format(
|
||||
UPDATED_AT_TIME_FORMAT
|
||||
)
|
||||
|
||||
return (
|
||||
<IndexList.Cell>
|
||||
<span title={absoluteTimestamp}>{relativeTimestamp}</span>
|
||||
</IndexList.Cell>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Libraries
|
||||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
import _ from 'lodash'
|
||||
|
||||
// APIs
|
||||
|
@ -17,18 +18,21 @@ import {Dashboard} from 'src/types/v2'
|
|||
// Decorators
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
interface OwnProps {
|
||||
dashboards: Dashboard[]
|
||||
orgName: string
|
||||
orgID: string
|
||||
onChange: () => void
|
||||
}
|
||||
|
||||
type Props = OwnProps & WithRouterProps
|
||||
|
||||
interface State {
|
||||
searchTerm: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
export default class Dashboards extends PureComponent<Props, State> {
|
||||
class Dashboards extends PureComponent<Props, State> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
@ -38,7 +42,7 @@ export default class Dashboards extends PureComponent<Props, State> {
|
|||
|
||||
public render() {
|
||||
const {searchTerm} = this.state
|
||||
const {dashboards} = this.props
|
||||
const {dashboards, orgID, router} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -62,6 +66,8 @@ export default class Dashboards extends PureComponent<Props, State> {
|
|||
dashboards={ds}
|
||||
emptyState={this.emptyState}
|
||||
onDeleteDashboard={this.handleDeleteDashboard}
|
||||
orgID={orgID}
|
||||
router={router}
|
||||
/>
|
||||
)}
|
||||
</FilterList>
|
||||
|
@ -104,3 +110,5 @@ export default class Dashboards extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter<OwnProps>(Dashboards)
|
||||
|
|
|
@ -131,6 +131,7 @@ class OrganizationView extends PureComponent<Props> {
|
|||
dashboards={dashboards}
|
||||
orgName={org.name}
|
||||
onChange={fetch}
|
||||
orgID={org.id}
|
||||
/>
|
||||
</Spinner>
|
||||
)}
|
||||
|
|
Loading…
Reference in New Issue