Skip to content

Commit

Permalink
feat(ui): Persist variables control bar preferences
Browse files Browse the repository at this point in the history
  • Loading branch information
ischolten committed Mar 26, 2019
1 parent 5a014dc commit 3b3fe0f
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 70 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
1. [12876](https://github.com/influxdata/influxdb/pull/12876): Add the ability to update token's status in Token list
1. [12821](https://github.com/influxdata/influxdb/pull/12821): Allow variables to be re-ordered within control bar on a dashboard.
1. [12888](https://github.com/influxdata/influxdb/pull/12888): Add the ability to delete a template
1. [12901](https://github.com/influxdata/influxdb/pull/12901): Save user preference for variable control bar visibility and default to visible

### Bug Fixes

Expand Down
10 changes: 9 additions & 1 deletion ui/src/dashboards/actions/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {RemoteDataState} from 'src/types'
import {Dispatch} from 'redux'
import {View} from 'src/types'

export type Action = SetViewAction | SetViewsAction
export type Action = SetViewAction | SetViewsAction | ResetViewsAction

export interface SetViewsAction {
type: 'SET_VIEWS'
Expand Down Expand Up @@ -45,6 +45,14 @@ export const setView = (
payload: {id, view, status},
})

export interface ResetViewsAction {
type: 'RESET_VIEWS'
}

export const resetViews = (): ResetViewsAction => ({
type: 'RESET_VIEWS',
})

export const getView = (dashboardID: string, cellID: string) => async (
dispatch: Dispatch<Action>
): Promise<void> => {
Expand Down
1 change: 0 additions & 1 deletion ui/src/dashboards/components/DashboardHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ interface Props extends DefaultProps {
onManualRefresh: () => void
handleClickPresentationButton: AppActions.DelayEnablePresentationModeDispatcher
onAddCell: () => void
showTemplateControlBar: boolean
onRenameDashboard: (name: string) => Promise<void>
toggleVariablesControlBar: () => void
isShowingVariablesControlBar: boolean
Expand Down
31 changes: 12 additions & 19 deletions ui/src/dashboards/components/DashboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {Location} from 'history'
import * as AppActions from 'src/types/actions/app'
import * as ColorsModels from 'src/types/colors'
import * as NotificationsActions from 'src/types/actions/notifications'
import {toggleShowVariablesControls} from 'src/userSettings/actions'

interface StateProps {
links: Links
Expand All @@ -45,7 +46,7 @@ interface StateProps {
dashboard: Dashboard
autoRefresh: number
inPresentationMode: boolean
showTemplateControlBar: boolean
showVariablesControls: boolean
views: {[cellID: string]: {view: View; status: RemoteDataState}}
}

Expand All @@ -64,6 +65,7 @@ interface DispatchProps {
onCreateCellWithView: typeof dashboardActions.createCellWithView
onUpdateView: typeof dashboardActions.updateView
onSetActiveTimeMachine: typeof setActiveTimeMachine
onToggleShowVariablesControls: typeof toggleShowVariablesControls
}

interface PassedProps {
Expand All @@ -90,8 +92,6 @@ type Props = PassedProps &
interface State {
scrollTop: number
windowHeight: number
isShowingVEO: boolean
isShowingVariablesControlBar: boolean
}

@ErrorHandling
Expand All @@ -102,8 +102,6 @@ class DashboardPage extends Component<Props, State> {
this.state = {
scrollTop: 0,
windowHeight: window.innerHeight,
isShowingVEO: false,
isShowingVariablesControlBar: false,
}
}

Expand Down Expand Up @@ -142,17 +140,17 @@ class DashboardPage extends Component<Props, State> {
const {
timeRange,
zoomedTimeRange,
showTemplateControlBar,
dashboard,
autoRefresh,
manualRefresh,
onManualRefresh,
inPresentationMode,
showVariablesControls,
handleChooseAutoRefresh,
handleClickPresentationButton,
onToggleShowVariablesControls,
children,
} = this.props
const {isShowingVariablesControlBar} = this.state

return (
<Page titleTag={this.pageTitle}>
Expand All @@ -168,14 +166,13 @@ class DashboardPage extends Component<Props, State> {
zoomedTimeRange={zoomedTimeRange}
onRenameDashboard={this.handleRenameDashboard}
activeDashboard={dashboard ? dashboard.name : ''}
showTemplateControlBar={showTemplateControlBar}
handleChooseAutoRefresh={handleChooseAutoRefresh}
handleChooseTimeRange={this.handleChooseTimeRange}
handleClickPresentationButton={handleClickPresentationButton}
toggleVariablesControlBar={this.toggleVariablesControlBar}
isShowingVariablesControlBar={isShowingVariablesControlBar}
toggleVariablesControlBar={onToggleShowVariablesControls}
isShowingVariablesControlBar={showVariablesControls}
/>
{isShowingVariablesControlBar && (
{showVariablesControls && !!dashboard && (
<VariablesControlBar dashboardID={dashboard.id} />
)}
{!!dashboard && (
Expand Down Expand Up @@ -292,12 +289,6 @@ class DashboardPage extends Component<Props, State> {
this.setState({windowHeight: window.innerHeight})
}

private toggleVariablesControlBar = (): void => {
this.setState({
isShowingVariablesControlBar: !this.state.isShowingVariablesControlBar,
})
}

private get pageTitle(): string {
const {dashboard} = this.props

Expand All @@ -310,11 +301,12 @@ const mstp = (state: AppState, {params: {dashboardID}}): StateProps => {
links,
app: {
ephemeral: {inPresentationMode},
persisted: {autoRefresh, showTemplateControlBar},
persisted: {autoRefresh},
},
ranges,
dashboards,
views: {views},
userSettings: {showVariablesControls},
} = state

const timeRange =
Expand All @@ -330,7 +322,7 @@ const mstp = (state: AppState, {params: {dashboardID}}): StateProps => {
dashboard,
autoRefresh,
inPresentationMode,
showTemplateControlBar,
showVariablesControls,
}
}

Expand All @@ -349,6 +341,7 @@ const mdtp: DispatchProps = {
onCreateCellWithView: dashboardActions.createCellWithView,
onUpdateView: dashboardActions.updateView,
onSetActiveTimeMachine: setActiveTimeMachine,
onToggleShowVariablesControls: toggleShowVariablesControls,
}

export default connect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {AppState, Dashboard} from 'src/types'

// Constants
import {DEFAULT_DASHBOARD_NAME} from 'src/dashboards/constants'
import {resetViews} from 'src/dashboards/actions/views'

interface PassedProps {
dashboard: Dashboard
Expand All @@ -44,6 +45,7 @@ interface DispatchProps {
onAddDashboardLabels: typeof addDashboardLabelsAsync
onRemoveDashboardLabels: typeof removeDashboardLabelsAsync
onCreateLabel: typeof createLabelAsync
onResetViews: typeof resetViews
}

type Props = PassedProps & DispatchProps & StateProps & WithRouterProps
Expand Down Expand Up @@ -145,7 +147,9 @@ class DashboardCard extends PureComponent<Props> {
}

private handleClickDashboard = () => {
const {router, dashboard} = this.props
const {router, dashboard, onResetViews} = this.props

onResetViews()

router.push(`/dashboards/${dashboard.id}`)
}
Expand Down Expand Up @@ -203,6 +207,7 @@ const mdtp: DispatchProps = {
onCreateLabel: createLabelAsync,
onAddDashboardLabels: addDashboardLabelsAsync,
onRemoveDashboardLabels: removeDashboardLabelsAsync,
onResetViews: resetViews,
}

export default connect<StateProps, DispatchProps, PassedProps>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,13 @@ $variables-control-bar--gutter: $ix-marg-a;
.variable-dropdown {
margin: 0 $variables-control-bar--gutter / 2;
}

.variables-spinner-container {
height: $variables-control-bar--height;
}
}


.variables-control-bar--empty {
background-color: $g3-castle;
border-radius: $radius;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import HTML5Backend from 'react-dnd-html5-backend'

// Components
import {EmptyState, ComponentSize} from 'src/clockface'
import {TechnoSpinner} from '@influxdata/clockface'
import {TechnoSpinner, SpinnerContainer} from '@influxdata/clockface'

// Utils
import {
getVariablesForDashboard,
getDashboardValuesStatus,
getDashboardVariablesStatus,
} from 'src/variables/selectors'

// Styles
Expand All @@ -37,34 +38,62 @@ interface OwnProps {
interface StateProps {
variables: Variable[]
valuesStatus: RemoteDataState
variablesStatus: RemoteDataState
}

interface DispatchProps {
moveVariable: typeof moveVariable
}

interface State {
initialLoading: RemoteDataState
}

type Props = StateProps & DispatchProps & OwnProps

@ErrorHandling
class VariablesControlBar extends PureComponent<Props> {
render() {
const {dashboardID, variables, valuesStatus} = this.props

if (isEmpty(variables)) {
return (
<div className="variables-control-bar">
<EmptyState
size={ComponentSize.ExtraSmall}
customClass="variables-control-bar--empty"
>
<EmptyState.Text text="To see variable controls here, use a variable in a cell query" />
</EmptyState>
</div>
)
class VariablesControlBar extends PureComponent<Props, State> {
public state: State = {initialLoading: RemoteDataState.Loading}

static getDerivedStateFromProps(props, state) {
if (
props.valuesStatus === RemoteDataState.Done &&
props.variablesStatus === RemoteDataState.Done &&
state.initialLoading !== RemoteDataState.Done
) {
return {initialLoading: RemoteDataState.Done}
}
}

render() {
return (
<div className="variables-control-bar">
<SpinnerContainer
loading={this.state.initialLoading}
spinnerComponent={<TechnoSpinner diameterPixels={50} />}
className="variables-spinner-container"
>
{this.bar}
</SpinnerContainer>
</div>
)
}

private get emptyBar(): JSX.Element {
return (
<EmptyState
size={ComponentSize.ExtraSmall}
customClass="variables-control-bar--empty"
>
<EmptyState.Text text="To see variable controls here, use a variable in a cell query" />
</EmptyState>
)
}

private get barContents(): JSX.Element {
const {dashboardID, variables, valuesStatus} = this.props
return (
<>
{variables.map((v, i) => (
<DraggableDropdown
key={v.id}
Expand All @@ -78,10 +107,20 @@ class VariablesControlBar extends PureComponent<Props> {
{valuesStatus === RemoteDataState.Loading && (
<TechnoSpinner diameterPixels={18} />
)}
</div>
</>
)
}

private get bar(): JSX.Element {
const {variables} = this.props

if (isEmpty(variables)) {
return this.emptyBar
}

return this.barContents
}

private handleMoveDropdown = (
originalIndex: number,
newIndex: number
Expand All @@ -98,8 +137,9 @@ const mdtp = {
const mstp = (state: AppState, props: OwnProps): StateProps => {
const variables = getVariablesForDashboard(state, props.dashboardID)
const valuesStatus = getDashboardValuesStatus(state, props.dashboardID)
const variablesStatus = getDashboardVariablesStatus(state)

return {variables, valuesStatus}
return {variables, valuesStatus, variablesStatus}
}

export default DragDropContext(HTML5Backend)(
Expand Down
4 changes: 4 additions & 0 deletions ui/src/dashboards/reducers/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ const viewsReducer = (
},
}
}

case 'RESET_VIEWS': {
return initialState()
}
}

return state
Expand Down
2 changes: 2 additions & 0 deletions ui/src/localStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const saveToLocalStorage = ({
app: {persisted},
ranges,
variables,
userSettings,
}: LocalStorage): void => {
try {
const appPersisted = {app: {persisted}}
Expand All @@ -41,6 +42,7 @@ export const saveToLocalStorage = ({
VERSION,
ranges: normalizer(ranges),
variables,
userSettings,
})
)
} catch (err) {
Expand Down
6 changes: 4 additions & 2 deletions ui/src/mockState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {Provider} from 'react-redux'
import {Router, createMemoryHistory} from 'react-router'

import {render} from 'react-testing-library'
import {initialState} from 'src/variables/reducers'
import {initialState as initialVariablesState} from 'src/variables/reducers'
import {initialState as initialUserSettingsState} from 'src/userSettings/reducers'
import configureStore from 'src/store/configureStore'

const localState = {
Expand All @@ -25,7 +26,8 @@ const localState = {
duration: '15m',
},
],
variables: initialState(),
variables: initialVariablesState(),
userSettings: initialUserSettingsState(),
}

const history = createMemoryHistory({entries: ['/']})
Expand Down
Loading

0 comments on commit 3b3fe0f

Please sign in to comment.