Merge pull request #12608 from influxdata/dashboard-import-routes
Dashboard import routespull/12621/head
commit
a9cc62778b
|
@ -0,0 +1,83 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
import _ from 'lodash'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Actions
|
||||
import {getDashboardsAsync} from 'src/dashboards/actions/v2'
|
||||
import {createDashboardFromTemplate as createDashboardFromTemplateAction} from 'src/dashboards/actions/v2'
|
||||
|
||||
// Types
|
||||
import ImportOverlay from 'src/shared/components/ImportOverlay'
|
||||
import {AppState, Organization} from 'src/types/v2'
|
||||
|
||||
interface DispatchProps {
|
||||
createDashboardFromTemplate: typeof createDashboardFromTemplateAction
|
||||
populateDashboards: typeof getDashboardsAsync
|
||||
}
|
||||
|
||||
interface StateProps {
|
||||
orgs: Organization[]
|
||||
}
|
||||
|
||||
interface OwnProps extends WithRouterProps {
|
||||
params: {orgID: string}
|
||||
}
|
||||
|
||||
type Props = OwnProps & StateProps & DispatchProps
|
||||
|
||||
class DashboardImportOverlay extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<ImportOverlay
|
||||
isVisible={true}
|
||||
onDismissOverlay={this.onDismiss}
|
||||
resourceName="Dashboard"
|
||||
onSubmit={this.handleImportDashboard}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private handleImportDashboard = async (
|
||||
uploadContent: string
|
||||
): Promise<void> => {
|
||||
const {
|
||||
createDashboardFromTemplate,
|
||||
populateDashboards,
|
||||
params: {orgID},
|
||||
orgs,
|
||||
} = this.props
|
||||
const template = JSON.parse(uploadContent)
|
||||
|
||||
if (_.isEmpty(template)) {
|
||||
this.onDismiss()
|
||||
}
|
||||
|
||||
await createDashboardFromTemplate(template, orgID || orgs[0].id)
|
||||
|
||||
await populateDashboards()
|
||||
|
||||
this.onDismiss()
|
||||
}
|
||||
|
||||
private onDismiss = (): void => {
|
||||
const {router} = this.props
|
||||
router.goBack()
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
createDashboardFromTemplate: createDashboardFromTemplateAction,
|
||||
populateDashboards: getDashboardsAsync,
|
||||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {orgs} = state
|
||||
return {orgs}
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps, OwnProps>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(withRouter(DashboardImportOverlay))
|
|
@ -1,79 +0,0 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Constants
|
||||
import {dashboardImportFailed} from 'src/shared/copy/notifications'
|
||||
|
||||
// Actions
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
import {getDashboardsAsync} from 'src/dashboards/actions/v2'
|
||||
|
||||
// Types
|
||||
import ImportOverlay from 'src/shared/components/ImportOverlay'
|
||||
import {createDashboardFromTemplate as createDashboardFromTemplateAction} from 'src/dashboards/actions/v2'
|
||||
|
||||
interface OwnProps {
|
||||
onDismissOverlay: () => void
|
||||
isVisible: boolean
|
||||
}
|
||||
interface DispatchProps {
|
||||
notify: typeof notifyAction
|
||||
createDashboardFromTemplate: typeof createDashboardFromTemplateAction
|
||||
populateDashboards: typeof getDashboardsAsync
|
||||
}
|
||||
|
||||
type Props = OwnProps & DispatchProps
|
||||
|
||||
class ImportDashboardOverlay extends PureComponent<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {isVisible, onDismissOverlay} = this.props
|
||||
|
||||
return (
|
||||
<ImportOverlay
|
||||
isVisible={isVisible}
|
||||
onDismissOverlay={onDismissOverlay}
|
||||
resourceName="Dashboard"
|
||||
onSubmit={this.handleUploadDashboard}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private handleUploadDashboard = async (
|
||||
uploadContent: string,
|
||||
orgID: string
|
||||
): Promise<void> => {
|
||||
const {
|
||||
notify,
|
||||
createDashboardFromTemplate,
|
||||
onDismissOverlay,
|
||||
populateDashboards,
|
||||
} = this.props
|
||||
|
||||
try {
|
||||
const template = JSON.parse(uploadContent)
|
||||
|
||||
await createDashboardFromTemplate(template, orgID)
|
||||
await populateDashboards()
|
||||
|
||||
onDismissOverlay()
|
||||
} catch (error) {
|
||||
notify(dashboardImportFailed(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
const mdtp: DispatchProps = {
|
||||
notify: notifyAction,
|
||||
createDashboardFromTemplate: createDashboardFromTemplateAction,
|
||||
populateDashboards: getDashboardsAsync,
|
||||
}
|
||||
|
||||
export default connect<{}, DispatchProps, OwnProps>(
|
||||
null,
|
||||
mdtp
|
||||
)(ImportDashboardOverlay)
|
|
@ -8,7 +8,6 @@ import DashboardsIndexContents from 'src/dashboards/components/dashboard_index/D
|
|||
import {Page} from 'src/pageLayout'
|
||||
import SearchWidget from 'src/shared/components/search_widget/SearchWidget'
|
||||
import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
|
||||
import ImportDashboardOverlay from 'src/dashboards/components/ImportDashboardOverlay'
|
||||
|
||||
// APIs
|
||||
import {createDashboard, cloneDashboard} from 'src/dashboards/apis/v2/'
|
||||
|
@ -64,7 +63,6 @@ type Props = DispatchProps & StateProps & OwnProps
|
|||
|
||||
interface State {
|
||||
searchTerm: string
|
||||
isImportingDashboard: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -74,7 +72,6 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
|
||||
this.state = {
|
||||
searchTerm: '',
|
||||
isImportingDashboard: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +96,7 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
<Page.Header.Right>
|
||||
<AddResourceDropdown
|
||||
onSelectNew={this.handleCreateDashboard}
|
||||
onSelectImport={this.handleToggleImportOverlay}
|
||||
onSelectImport={this.summonImportOverlay}
|
||||
resourceName="Dashboard"
|
||||
/>
|
||||
</Page.Header.Right>
|
||||
|
@ -130,7 +127,7 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
{this.importOverlay}
|
||||
{this.props.children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -191,19 +188,9 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
this.setState({searchTerm})
|
||||
}
|
||||
|
||||
private handleToggleImportOverlay = (): void => {
|
||||
this.setState({isImportingDashboard: !this.state.isImportingDashboard})
|
||||
}
|
||||
|
||||
private get importOverlay(): JSX.Element {
|
||||
const {isImportingDashboard} = this.state
|
||||
|
||||
return (
|
||||
<ImportDashboardOverlay
|
||||
onDismissOverlay={this.handleToggleImportOverlay}
|
||||
isVisible={isImportingDashboard}
|
||||
/>
|
||||
)
|
||||
private summonImportOverlay = (): void => {
|
||||
const {router} = this.props
|
||||
router.push(`/dashboards/import`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import TaskEditPage from 'src/tasks/containers/TaskEditPage'
|
|||
import DashboardPage from 'src/dashboards/components/DashboardPage'
|
||||
import DashboardsIndex from 'src/dashboards/components/dashboard_index/DashboardsIndex'
|
||||
import DashboardExportOverlay from 'src/dashboards/components/DashboardExportOverlay'
|
||||
import DashboardImportOverlay from 'src/dashboards/components/DashboardImportOverlay'
|
||||
import DataExplorerPage from 'src/dataExplorer/components/DataExplorerPage'
|
||||
import {MePage, Account} from 'src/me'
|
||||
import NotFound from 'src/shared/components/NotFound'
|
||||
|
@ -114,12 +115,18 @@ class Root extends PureComponent {
|
|||
<IndexRoute component={OrganizationsIndex} />
|
||||
<Route path=":orgID">
|
||||
<Route path="buckets" component={OrgBucketIndex} />
|
||||
<Route path="dashboards">
|
||||
<IndexRoute component={OrgDashboardsIndex} />
|
||||
<Route
|
||||
path="dashboards"
|
||||
component={OrgDashboardsIndex}
|
||||
>
|
||||
<Route
|
||||
path=":dashboardID/export"
|
||||
component={DashboardExportOverlay}
|
||||
/>
|
||||
<Route
|
||||
path="import"
|
||||
component={DashboardImportOverlay}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="members" component={OrgMembersIndex} />
|
||||
<Route
|
||||
|
@ -165,17 +172,20 @@ class Root extends PureComponent {
|
|||
path="data-explorer"
|
||||
component={DataExplorerPage}
|
||||
/>
|
||||
<Route path="dashboards">
|
||||
<IndexRoute component={DashboardsIndex} />
|
||||
<Route
|
||||
path=":dashboardID"
|
||||
component={DashboardPage}
|
||||
/>
|
||||
<Route path="dashboards" component={DashboardsIndex}>
|
||||
<Route
|
||||
path=":dashboardID/export"
|
||||
component={DashboardExportOverlay}
|
||||
/>
|
||||
<Route
|
||||
path="import"
|
||||
component={DashboardImportOverlay}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="dashboards/:dashboardID"
|
||||
component={DashboardPage}
|
||||
/>
|
||||
<Route path="me" component={MePage} />
|
||||
<Route path="account/:tab" component={Account} />
|
||||
<Route
|
||||
|
|
|
@ -8,7 +8,6 @@ import _ from 'lodash'
|
|||
import DashboardsIndexContents from 'src/dashboards/components/dashboard_index/DashboardsIndexContents'
|
||||
import {Input, Tabs} from 'src/clockface'
|
||||
import {IconFont} from '@influxdata/clockface'
|
||||
import ImportDashboardOverlay from 'src/dashboards/components/ImportDashboardOverlay'
|
||||
import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
|
||||
|
||||
// APIs
|
||||
|
@ -71,7 +70,6 @@ type Props = DispatchProps & StateProps & OwnProps & WithRouterProps
|
|||
|
||||
interface State {
|
||||
searchTerm: string
|
||||
isImportingDashboard: boolean
|
||||
isEditingDashboardLabels: boolean
|
||||
dashboardLabelsEdit: Dashboard
|
||||
}
|
||||
|
@ -83,7 +81,6 @@ class Dashboards extends PureComponent<Props, State> {
|
|||
|
||||
this.state = {
|
||||
searchTerm: '',
|
||||
isImportingDashboard: false,
|
||||
isEditingDashboardLabels: false,
|
||||
dashboardLabelsEdit: null,
|
||||
}
|
||||
|
@ -115,7 +112,7 @@ class Dashboards extends PureComponent<Props, State> {
|
|||
/>
|
||||
<AddResourceDropdown
|
||||
onSelectNew={this.handleCreateDashboard}
|
||||
onSelectImport={this.handleToggleOverlay}
|
||||
onSelectImport={this.handleImport}
|
||||
resourceName="Dashboard"
|
||||
/>
|
||||
</Tabs.TabContentsHeader>
|
||||
|
@ -133,7 +130,6 @@ class Dashboards extends PureComponent<Props, State> {
|
|||
showOwnerColumn={false}
|
||||
onFilterChange={this.handleFilterUpdate}
|
||||
/>
|
||||
{this.renderImportOverlay}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -149,6 +145,12 @@ class Dashboards extends PureComponent<Props, State> {
|
|||
private handleFilterUpdate = (searchTerm: string): void => {
|
||||
this.setState({searchTerm})
|
||||
}
|
||||
|
||||
private handleImport = (): void => {
|
||||
const {router, params} = this.props
|
||||
router.push(`/organizations/${params.orgID}/dashboards/import`)
|
||||
}
|
||||
|
||||
private handleSetDefaultDashboard = async (
|
||||
defaultDashboardLink: string
|
||||
): Promise<void> => {
|
||||
|
@ -200,21 +202,6 @@ class Dashboards extends PureComponent<Props, State> {
|
|||
private handleDeleteDashboard = (dashboard: Dashboard) => {
|
||||
this.props.handleDeleteDashboard(dashboard)
|
||||
}
|
||||
|
||||
private handleToggleOverlay = (): void => {
|
||||
this.setState({isImportingDashboard: !this.state.isImportingDashboard})
|
||||
}
|
||||
|
||||
private get renderImportOverlay(): JSX.Element {
|
||||
const {isImportingDashboard} = this.state
|
||||
|
||||
return (
|
||||
<ImportDashboardOverlay
|
||||
onDismissOverlay={this.handleToggleOverlay}
|
||||
isVisible={isImportingDashboard}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
|
@ -242,4 +229,4 @@ const mdtp: DispatchProps = {
|
|||
export default connect<StateProps, DispatchProps, OwnProps>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(withRouter<OwnProps>(Dashboards))
|
||||
)(withRouter(Dashboards))
|
||||
|
|
|
@ -7,17 +7,11 @@ import {get} from 'lodash'
|
|||
import ImportOverlay from 'src/shared/components/ImportOverlay'
|
||||
|
||||
// Actions
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
import {createTaskFromTemplate as createTaskFromTemplateAction} from 'src/organizations/actions/orgView'
|
||||
import {getTasks as getTasksAction} from 'src/organizations/actions/orgView'
|
||||
import {populateTasks as populateTasksAction} from 'src/tasks/actions/v2'
|
||||
import {
|
||||
importTaskFailed,
|
||||
importTaskSucceeded,
|
||||
} from 'src/shared/copy/notifications'
|
||||
|
||||
interface DispatchProps {
|
||||
notify: typeof notifyAction
|
||||
createTaskFromTemplate: typeof createTaskFromTemplateAction
|
||||
getTasks: typeof getTasksAction
|
||||
populateTasks: typeof populateTasksAction
|
||||
|
@ -50,7 +44,7 @@ class TaskImportOverlay extends PureComponent<Props> {
|
|||
importString: string,
|
||||
orgID: string
|
||||
): Promise<void> => {
|
||||
const {createTaskFromTemplate, getTasks, populateTasks, notify} = this.props
|
||||
const {createTaskFromTemplate, getTasks, populateTasks} = this.props
|
||||
|
||||
try {
|
||||
const template = JSON.parse(importString)
|
||||
|
@ -64,17 +58,13 @@ class TaskImportOverlay extends PureComponent<Props> {
|
|||
// import overlay is in tasks view
|
||||
populateTasks()
|
||||
}
|
||||
} catch (error) {}
|
||||
|
||||
this.onDismiss()
|
||||
notify(importTaskSucceeded())
|
||||
} catch (error) {
|
||||
notify(importTaskFailed(error))
|
||||
}
|
||||
this.onDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
notify: notifyAction,
|
||||
createTaskFromTemplate: createTaskFromTemplateAction,
|
||||
getTasks: getTasksAction,
|
||||
populateTasks: populateTasksAction,
|
||||
|
|
|
@ -43,50 +43,49 @@ type Props = WithRouterProps & RouterProps & DispatchProps & StateProps
|
|||
|
||||
@ErrorHandling
|
||||
class OrgDashboardsIndex extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {org} = this.props
|
||||
|
||||
return (
|
||||
<Page titleTag={org.name}>
|
||||
<OrgHeader orgID={org.id} />
|
||||
<Page.Contents fullWidth={false} scrollable={true}>
|
||||
<div className="col-xs-12">
|
||||
<Tabs>
|
||||
<OrganizationNavigation tab={'dashboards'} orgID={org.id} />
|
||||
<Tabs.TabContents>
|
||||
<TabbedPageSection
|
||||
id="org-view-tab--dashboards"
|
||||
url="dashboards"
|
||||
title="Dashboards"
|
||||
>
|
||||
<GetOrgResources<Dashboard>
|
||||
organization={org}
|
||||
fetcher={getDashboards}
|
||||
<>
|
||||
<Page titleTag={org.name}>
|
||||
<OrgHeader orgID={org.id} />
|
||||
<Page.Contents fullWidth={false} scrollable={true}>
|
||||
<div className="col-xs-12">
|
||||
<Tabs>
|
||||
<OrganizationNavigation tab={'dashboards'} orgID={org.id} />
|
||||
<Tabs.TabContents>
|
||||
<TabbedPageSection
|
||||
id="org-view-tab--dashboards"
|
||||
url="dashboards"
|
||||
title="Dashboards"
|
||||
>
|
||||
{(dashboards, loading, fetch) => (
|
||||
<SpinnerContainer
|
||||
loading={loading}
|
||||
spinnerComponent={<TechnoSpinner />}
|
||||
>
|
||||
<Dashboards
|
||||
dashboards={dashboards}
|
||||
orgName={org.name}
|
||||
onChange={fetch}
|
||||
orgID={org.id}
|
||||
/>
|
||||
</SpinnerContainer>
|
||||
)}
|
||||
</GetOrgResources>
|
||||
</TabbedPageSection>
|
||||
</Tabs.TabContents>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
<GetOrgResources<Dashboard>
|
||||
organization={org}
|
||||
fetcher={getDashboards}
|
||||
>
|
||||
{(dashboards, loading, fetch) => (
|
||||
<SpinnerContainer
|
||||
loading={loading}
|
||||
spinnerComponent={<TechnoSpinner />}
|
||||
>
|
||||
<Dashboards
|
||||
dashboards={dashboards}
|
||||
orgName={org.name}
|
||||
onChange={fetch}
|
||||
orgID={org.id}
|
||||
/>
|
||||
</SpinnerContainer>
|
||||
)}
|
||||
</GetOrgResources>
|
||||
</TabbedPageSection>
|
||||
</Tabs.TabContents>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
{this.props.children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue