Skip to content

Commit

Permalink
refactor(dashboards): sorting
Browse files Browse the repository at this point in the history
* wip: sort via selectors

* wip: selector sort

* feat: store sort order locally

* chore: remove empty test

* fix: type error

* fix(clockface): have resource body return empty state when children are false

* chore: add type for list
  • Loading branch information
121watts authored Mar 26, 2019
1 parent 872092d commit bbe2fe4
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 77 deletions.
5 changes: 5 additions & 0 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@
"redux": "^4.0.0",
"redux-auth-wrapper": "^1.0.0",
"redux-thunk": "^1.0.3",
"reselect": "^4.0.0",
"rome": "^2.1.22",
"ui": "^0.2.4",
"uuid": "^3.2.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ export default class ResourceListBody extends PureComponent<Props> {

private get children(): JSX.Element | JSX.Element[] {
const {children, emptyState} = this.props

if (React.Children.count(children) === 0) {
if (React.Children.count(children) === 0 || children === false) {
return emptyState
}

Expand Down
77 changes: 63 additions & 14 deletions ui/src/dashboards/components/dashboard_index/DashboardCards.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,56 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'

// Components
import DashboardCard from 'src/dashboards/components/dashboard_index/DashboardCard'

// Selectors
import {getSortedResource} from 'src/shared/selectors/sort'

// Types
import {Dashboard} from 'src/types'
import {Dashboard, AppState} from 'src/types'
import {Sort} from 'src/clockface'

interface Props {
interface OwnProps {
dashboards: Dashboard[]
sortKey: string
sortDirection: Sort
sortType: SortTypes
onDeleteDashboard: (dashboard: Dashboard) => void
onCloneDashboard: (dashboard: Dashboard) => void
onUpdateDashboard: (dashboard: Dashboard) => void
showOwnerColumn: boolean
onFilterChange: (searchTerm: string) => void
}

export default class DashboardCards extends PureComponent<Props> {
interface StateProps {
sortedIDs: string[]
}

export enum SortTypes {
String = 'string',
Date = 'date',
}

type Props = OwnProps & StateProps

class DashboardCards extends PureComponent<Props> {
public state = {
sortedIDs: this.props.sortedIDs,
}

componentDidUpdate(prevProps) {
const {sortDirection, sortKey, sortedIDs} = this.props

if (
prevProps.sortDirection !== sortDirection ||
prevProps.sortKey !== sortKey
) {
this.setState({sortedIDs})
}
}

public render() {
const {
dashboards,
Expand All @@ -27,16 +61,31 @@ export default class DashboardCards extends PureComponent<Props> {
onFilterChange,
} = this.props

return dashboards.map(d => (
<DashboardCard
key={d.id}
dashboard={d}
onCloneDashboard={onCloneDashboard}
onDeleteDashboard={onDeleteDashboard}
onUpdateDashboard={onUpdateDashboard}
showOwnerColumn={showOwnerColumn}
onFilterChange={onFilterChange}
/>
))
const {sortedIDs} = this.state

return sortedIDs.map(id => {
const dashboard = dashboards.find(d => d.id === id)
return (
dashboard && (
<DashboardCard
key={id}
dashboard={dashboard}
onCloneDashboard={onCloneDashboard}
onDeleteDashboard={onDeleteDashboard}
onUpdateDashboard={onUpdateDashboard}
showOwnerColumn={showOwnerColumn}
onFilterChange={onFilterChange}
/>
)
)
})
}
}

const mstp = (state: AppState, props: OwnProps) => {
return {
sortedIDs: getSortedResource(state.dashboards, props),
}
}

export default connect<StateProps, {}, OwnProps>(mstp)(DashboardCards)
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export default class DashboardsIndexContents extends Component<Props> {
>
{filteredDashboards => (
<Table
filterComponent={filterComponent}
searchTerm={searchTerm}
filterComponent={filterComponent}
dashboards={filteredDashboards}
onDeleteDashboard={onDeleteDashboard}
onCreateDashboard={onCreateDashboard}
Expand Down
102 changes: 42 additions & 60 deletions ui/src/dashboards/components/dashboard_index/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import _ from 'lodash'
import {ComponentSize} from '@influxdata/clockface'
import {EmptyState, ResourceList} from 'src/clockface'
import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
import DashboardCards from 'src/dashboards/components/dashboard_index/DashboardCards'
import SortingHat from 'src/shared/components/sorting_hat/SortingHat'
import DashboardCards, {
SortTypes,
} from 'src/dashboards/components/dashboard_index/DashboardCards'

// Types
import {Sort} from 'src/clockface'
import {Dashboard} from 'src/types'

interface Props {
interface OwnProps {
searchTerm: string
dashboards: Dashboard[]
onDeleteDashboard: (dashboard: Dashboard) => void
onCreateDashboard: () => void
onCloneDashboard: (dashboard: Dashboard) => void
Expand All @@ -25,31 +25,38 @@ interface Props {
showOwnerColumn: boolean
filterComponent?: () => JSX.Element
onImportDashboard: () => void
}

interface DatedDashboard extends Dashboard {
modified: Date
dashboards: Dashboard[]
}

interface State {
sortKey: SortKey
sortDirection: Sort
sortType: SortTypes
}

type SortKey = keyof Dashboard | 'modified' | 'owner' | 'default' // owner and modified are currently hardcoded

class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
constructor(props) {
super(props)
this.state = {
sortKey: null,
sortDirection: Sort.Descending,
}
type Props = OwnProps & WithRouterProps

class DashboardsTable extends PureComponent<Props, State> {
state: State = {
sortKey: 'name',
sortDirection: Sort.Ascending,
sortType: SortTypes.String,
}

public render() {
const {filterComponent} = this.props
const {sortKey, sortDirection} = this.state
const {
dashboards,
filterComponent,
onCloneDashboard,
onDeleteDashboard,
onUpdateDashboard,
showOwnerColumn,
onFilterChange,
} = this.props

const {sortKey, sortDirection, sortType} = this.state

return (
<ResourceList>
Expand All @@ -69,7 +76,19 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
/>
</ResourceList.Header>
<ResourceList.Body emptyState={this.emptyState}>
{this.sortedCards}
{!!dashboards.length && (
<DashboardCards
dashboards={dashboards}
sortKey={sortKey}
sortDirection={sortDirection}
sortType={sortType}
onCloneDashboard={onCloneDashboard}
onDeleteDashboard={onDeleteDashboard}
onUpdateDashboard={onUpdateDashboard}
showOwnerColumn={showOwnerColumn}
onFilterChange={onFilterChange}
/>
)}
</ResourceList.Body>
</ResourceList>
)
Expand All @@ -96,50 +115,13 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
}

private handleClickColumn = (nextSort: Sort, sortKey: SortKey) => {
this.setState({sortKey, sortDirection: nextSort})
}

private get sortedCards(): JSX.Element {
const {
dashboards,
onCloneDashboard,
onDeleteDashboard,
onUpdateDashboard,
showOwnerColumn,
onFilterChange,
} = this.props

const {sortKey, sortDirection} = this.state
let sortType = SortTypes.String

if (dashboards.length) {
return (
<SortingHat<DatedDashboard>
list={this.datedDashboards}
sortKey={sortKey}
direction={sortDirection}
>
{ds => (
<DashboardCards
dashboards={ds}
onCloneDashboard={onCloneDashboard}
onDeleteDashboard={onDeleteDashboard}
onUpdateDashboard={onUpdateDashboard}
showOwnerColumn={showOwnerColumn}
onFilterChange={onFilterChange}
/>
)}
</SortingHat>
)
if (sortKey === 'modified') {
sortType = SortTypes.Date
}

return null
}

private get datedDashboards(): DatedDashboard[] {
return this.props.dashboards.map(d => ({
...d,
modified: new Date(d.meta.updatedAt),
}))
this.setState({sortKey, sortDirection: nextSort, sortType})
}

private get emptyState(): JSX.Element {
Expand Down Expand Up @@ -169,4 +151,4 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
}
}

export default withRouter<Props>(DashboardsTable)
export default withRouter<OwnProps>(DashboardsTable)
37 changes: 37 additions & 0 deletions ui/src/shared/selectors/sort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {createSelector} from 'reselect'
import {orderBy, get} from 'lodash'

const resourceList = state => state

export const sortSelector = (_, props) => ({
key: props.sortKey,
direction: props.sortDirection,
type: props.sortType,
})

function orderByType(data, type) {
switch (type) {
case 'date':
return Date.parse(data)
case 'float':
return parseFloat(data)
default:
return data
}
}

export const getSortedResource = createSelector(
resourceList,
sortSelector,
(resourceList, sort) => {
if (sort.key && sort.direction) {
return orderBy<{id: string}>(
resourceList,
r => orderByType(get(r, sort.key), sort.type),
[sort.direction]
).map(r => r.id)
}

return resourceList
}
)

0 comments on commit bbe2fe4

Please sign in to comment.