Merge pull request #12608 from influxdata/dashboard-import-routes

Dashboard import routes
pull/12621/head
Deniz Kusefoglu 2019-03-13 18:26:39 -07:00 committed by GitHub
commit a9cc62778b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 155 additions and 178 deletions

View File

@ -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))

View File

@ -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)

View File

@ -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`)
}
}

View File

@ -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

View File

@ -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))

View File

@ -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,

View File

@ -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}
</>
)
}
}