VEO uses react router

Co-authored-by: Iris Scholten <ischolten.is@gmail.com>
pull/12618/head
Brandon Farmer 2019-03-13 17:13:30 -07:00
parent 966ff97735
commit 32ab5f54ac
7 changed files with 142 additions and 137 deletions

41
ui/package-lock.json generated
View File

@ -6106,8 +6106,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -6131,15 +6130,13 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -6156,22 +6153,19 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -6302,8 +6296,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -6317,7 +6310,6 @@
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -6334,7 +6326,6 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -6343,15 +6334,13 @@
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz",
"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@ -6372,7 +6361,6 @@
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -6461,8 +6449,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -6476,7 +6463,6 @@
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -6572,8 +6558,7 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@ -6615,7 +6600,6 @@
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -6637,7 +6621,6 @@
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -6686,15 +6669,13 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"dev": true,
"optional": true
"dev": true
}
}
},

View File

@ -63,7 +63,7 @@ export const updateView = (dashboardID: string, view: View) => async (
): Promise<View> => {
const viewID = view.cellID
dispatch(setView(viewID, null, RemoteDataState.Loading))
dispatch(setView(viewID, view, RemoteDataState.Loading))
try {
const newView = await updateViewAJAX(dashboardID, viewID, view)

View File

@ -10,8 +10,6 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
import DashboardHeader from 'src/dashboards/components/DashboardHeader'
import DashboardComponent from 'src/dashboards/components/Dashboard'
import ManualRefresh from 'src/shared/components/ManualRefresh'
import VEO from 'src/dashboards/components/VEO'
import {Overlay} from 'src/clockface'
import {HoverTimeProvider} from 'src/dashboards/utils/hoverTime'
import NoteEditorContainer from 'src/dashboards/components/NoteEditorContainer'
@ -25,25 +23,13 @@ import {setActiveTimeMachine} from 'src/timeMachine/actions'
// Utils
import {getDeep} from 'src/utils/wrappers'
import {GlobalAutoRefresher} from 'src/utils/AutoRefresher'
import {createView} from 'src/shared/utils/view'
import {cellAddFailed} from 'src/shared/copy/notifications'
// Constants
import {DASHBOARD_LAYOUT_ROW_HEIGHT} from 'src/shared/constants'
import {DEFAULT_TIME_RANGE} from 'src/shared/constants/timeRanges'
import {VEO_TIME_MACHINE_ID} from 'src/timeMachine/constants'
// Types
import {
Links,
Dashboard,
Cell,
View,
ViewType,
TimeRange,
AppState,
} from 'src/types/v2'
import {NewView, XYView, QueryViewProperties} from 'src/types/v2/dashboards'
import {Links, Dashboard, Cell, View, TimeRange, AppState} from 'src/types/v2'
import {RemoteDataState} from 'src/types'
import {WithRouterProps} from 'react-router'
import {ManualRefreshProps} from 'src/shared/components/ManualRefresh'
@ -162,8 +148,8 @@ class DashboardPage extends Component<Props, State> {
inPresentationMode,
handleChooseAutoRefresh,
handleClickPresentationButton,
children,
} = this.props
const {isShowingVEO} = this.state
return (
<Page titleTag={this.pageTitle}>
@ -200,9 +186,7 @@ class DashboardPage extends Component<Props, State> {
onAddCell={this.handleAddCell}
/>
)}
<Overlay visible={isShowingVEO} className="veo-overlay">
<VEO onHide={this.handleHideVEO} onSave={this.handleSaveVEO} />
</Overlay>
{children}
</HoverTimeProvider>
<NoteEditorContainer />
</Page>
@ -244,50 +228,19 @@ class DashboardPage extends Component<Props, State> {
}
private handleAddCell = async (): Promise<void> => {
const newView = createView<XYView>(ViewType.XY)
this.showVEO(newView)
}
private handleHideVEO = (): void => {
this.setState({isShowingVEO: false})
}
private handleSaveVEO = async (view: View): Promise<void> => {
this.setState({isShowingVEO: false})
const {dashboard, onCreateCellWithView, onUpdateView, notify} = this.props
try {
if (view.id) {
onUpdateView(dashboard, view)
} else {
await onCreateCellWithView(dashboard, view)
}
} catch (error) {
console.error(error)
notify(cellAddFailed())
}
this.showVEO()
}
private handleEditView = (cellID: string): void => {
const entry = this.props.views[cellID]
if (!entry || !entry.view) {
throw new Error(`Can't edit non-existent view with ID "${cellID}"`)
}
this.showVEO(entry.view as View<QueryViewProperties>)
this.showVEO(cellID)
}
private showVEO = (
view: View<QueryViewProperties> | NewView<QueryViewProperties>
): void => {
const {onSetActiveTimeMachine} = this.props
onSetActiveTimeMachine(VEO_TIME_MACHINE_ID, {view})
this.setState({isShowingVEO: true})
private showVEO = (id?: string): void => {
if (id) {
this.props.router.push(`${this.props.location.pathname}/cells/${id}/edit`)
} else {
this.props.router.push(`${this.props.location.pathname}/cells/new`)
}
}
private handleCloneCell = async (cell: Cell): Promise<void> => {

View File

@ -1,6 +1,10 @@
// Libraries
import React, {PureComponent} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import _ from 'lodash'
import {Overlay} from 'src/clockface'
// Components
import VEOHeader from 'src/dashboards/components/VEOHeader'
@ -8,58 +12,94 @@ import TimeMachine from 'src/timeMachine/components/TimeMachine'
// Actions
import {setName} from 'src/timeMachine/actions'
import * as viewActions from 'src/dashboards/actions/views'
import * as dashboardActions from 'src/dashboards/actions'
import {notify} from 'src/shared/actions/notifications'
// Utils
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
import {createView} from 'src/shared/utils/view'
// Types
import {AppState, DashboardQuery, View, NewView} from 'src/types/v2'
import {AppState, DashboardQuery, ViewType} from 'src/types/v2'
import {QueryView} from 'src/types/v2/dashboards'
import {Dashboard} from 'src/types'
import {XYView} from 'src/types/v2/dashboards'
import {setActiveTimeMachine} from 'src/timeMachine/actions'
// Constants
import {VEO_TIME_MACHINE_ID} from 'src/timeMachine/constants'
// Nofication Messages
import {cellAddFailed} from 'src/shared/copy/notifications'
// Styles
import './VEO.scss'
interface StateProps {
draftView: NewView
draftView: QueryView
existingView?: QueryView
draftQueries: DashboardQuery[]
dashboard: Dashboard
}
interface DispatchProps {
onSetName: typeof setName
onCreateCellWithView: typeof dashboardActions.createCellWithView
onUpdateView: typeof viewActions.updateView
notify: typeof notify
setActiveTimeMachine: typeof setActiveTimeMachine
}
interface OwnProps {
onHide: () => void
onSave: (v: NewView | View) => Promise<void>
interface OwnProps extends WithRouterProps {
params: {
dashboardID: string
cellID?: string
}
}
type Props = OwnProps & StateProps & DispatchProps
class VEO extends PureComponent<Props, {}> {
public render() {
const {draftView, onSetName, onHide} = this.props
const {draftView, onSetName} = this.props
return (
<div className="veo">
<VEOHeader
key={draftView.name}
name={draftView.name}
onSetName={onSetName}
onCancel={onHide}
onSave={this.handleSave}
/>
<div className="veo-contents">
<TimeMachine />
<Overlay visible={true} className="veo-overlay">
<div className="veo">
<VEOHeader
key={draftView.name}
name={draftView.name}
onSetName={onSetName}
onCancel={this.close}
onSave={this.handleSave}
/>
<div className="veo-contents">
<TimeMachine />
</div>
</div>
</div>
</Overlay>
)
}
private handleSave = (): void => {
const {draftView, draftQueries, onSave} = this.props
public async componentDidMount() {
const {existingView} = this.props
const view = existingView || createView<XYView>(ViewType.XY)
// Ensure that the latest queries are saved with the view, even if they
// haven't been submitted yet
const view = {
this.props.setActiveTimeMachine(VEO_TIME_MACHINE_ID, {view})
}
private handleSave = async (): Promise<void> => {
const {
draftView,
draftQueries,
dashboard,
onCreateCellWithView,
onUpdateView,
notify,
} = this.props
const view: QueryView & {id?: string} = {
...draftView,
properties: {
...draftView.properties,
@ -67,21 +107,49 @@ class VEO extends PureComponent<Props, {}> {
},
}
onSave(view)
try {
if (view.id) {
await onUpdateView(dashboard.id, view)
} else {
await onCreateCellWithView(dashboard, view)
}
this.close()
} catch (error) {
console.error(error)
notify(cellAddFailed())
}
}
private close = (): void => {
this.props.router.goBack()
}
}
const mstp = (state: AppState): StateProps => {
const mstp = (state: AppState, {params}): StateProps => {
const {cellID, dashboardID} = params
const {
views: {views},
dashboards,
} = state
const {view, draftQueries} = getActiveTimeMachine(state)
const dashboard = dashboards.find(d => d.id === dashboardID)
let existingView = null
if (cellID) {
existingView = _.get(views, [cellID, 'view'])
}
return {draftView: view, draftQueries}
return {draftView: view, existingView, draftQueries, dashboard}
}
const mdtp: DispatchProps = {
onSetName: setName,
onCreateCellWithView: dashboardActions.createCellWithView,
onUpdateView: viewActions.updateView,
setActiveTimeMachine,
notify,
}
export default connect<StateProps, DispatchProps, OwnProps>(
mstp,
mdtp
)(VEO)
)(withRouter<OwnProps, {}>(VEO))

View File

@ -2,8 +2,9 @@ import {get} from 'lodash'
import {AppState, View} from 'src/types/v2'
export const getView = (state: AppState, id: string): View =>
get(state, `views.views.${id}.view`)
export const getView = (state: AppState, id: string): View => {
return get(state, `views.views.${id}.view`)
}
export const getViewsForDashboard = (
state: AppState,

View File

@ -46,6 +46,7 @@ import OrgScrapersIndex from 'src/organizations/containers/OrgScrapersIndex'
import OrgTasksIndex from 'src/organizations/containers/OrgTasksIndex'
import TaskExportOverlay from 'src/organizations/components/TaskExportOverlay'
import TaskImportOverlay from 'src/organizations/components/TaskImportOverlay'
import VEO from 'src/dashboards/components/VEO'
import OnboardingWizardPage from 'src/onboarding/containers/OnboardingWizardPage'
@ -141,21 +142,20 @@ class Root extends PureComponent {
path="scrapers"
component={OrgScrapersIndex}
/>
<Route path="tasks" component={OrgTasksIndex}>
<Route
path="import"
component={TaskImportOverlay}
/>
<Route
path=":id/export"
component={TaskExportOverlay}
/>
<Route path="tasks">
<IndexRoute component={OrgTasksIndex}>
<Route
path="import"
component={TaskImportOverlay}
/>
<Route
path=":id/export"
component={TaskExportOverlay}
/>
</IndexRoute>
<Route path="new" component={OrgTaskPage} />
<Route path=":id" component={OrgTaskEditPage} />
</Route>
<Route path="tasks/new" component={OrgTaskPage} />
<Route
path="tasks/:id"
component={OrgTaskEditPage}
/>
</Route>
</Route>
<Route path="tasks" component={TasksPage}>
@ -172,7 +172,14 @@ class Root extends PureComponent {
path="data-explorer"
component={DataExplorerPage}
/>
<Route path="dashboards" component={DashboardsIndex}>
<Route path="dashboards">
<IndexRoute component={DashboardsIndex} />
<Route path=":dashboardID" component={DashboardPage}>
<Route path="cells">
<Route path="new" component={VEO} />
<Route path=":cellID/edit" component={VEO} />
</Route>
</Route>
<Route
path=":dashboardID/export"
component={DashboardExportOverlay}
@ -182,10 +189,6 @@ class Root extends PureComponent {
component={DashboardImportOverlay}
/>
</Route>
<Route
path="dashboards/:dashboardID"
component={DashboardPage}
/>
<Route path="me" component={MePage} />
<Route path="account/:tab" component={Account} />
<Route

View File

@ -50,7 +50,6 @@ const TimeMachine: FunctionComponent<StateProps> = ({activeTab}) => {
className="time-machine--bottom"
data-testid="time-machine--bottom"
>
{/* TODO: Is this div needed? */}
<div className="time-machine--bottom-contents">
<TimeMachineQueries />
</div>