Skip to content

Commit

Permalink
Add columns indicator (select columns) to table indicators
Browse files Browse the repository at this point in the history
  • Loading branch information
mattseddon committed Jul 18, 2023
1 parent 58802a6 commit 07f8adb
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 108 deletions.
250 changes: 146 additions & 104 deletions webview/src/experiments/components/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1584,136 +1584,178 @@ describe('App', () => {
expect(sortIndicator).toHaveTextContent('2')
jest.useRealTimers()
})
})

it('should show an indicator with the amount of applied filters', () => {
renderTable({
...tableDataFixture,
filters: []
})
jest.useFakeTimers()
const filterIndicator = screen.getByLabelText('filters')
expect(filterIndicator).toHaveTextContent('')
it('should show an indicator with the amount of applied filters', () => {
renderTable({
...tableDataFixture,
filters: []
})
jest.useFakeTimers()
const filterIndicator = screen.getByLabelText('filters')
expect(filterIndicator).toHaveTextContent('')

expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()

fireEvent.mouseEnter(filterIndicator)
advanceTimersByTime(1000)
fireEvent.mouseEnter(filterIndicator)
advanceTimersByTime(1000)

const tooltip = screen.getByRole('tooltip')
const tooltip = screen.getByRole('tooltip')

expect(tooltip).toHaveTextContent('Show Filters')
expect(tooltip).toHaveTextContent('Show Filters')

const { columns } = tableDataFixture
const firstFilterPath = columns[columns.length - 1].path
const secondFilterPath = columns[columns.length - 2].path
setTableData({
...tableDataFixture,
filters: [firstFilterPath]
})
expect(filterIndicator).toHaveTextContent('1')
const { columns } = tableDataFixture
const firstFilterPath = columns[columns.length - 1].path
const secondFilterPath = columns[columns.length - 2].path
setTableData({
...tableDataFixture,
filters: [firstFilterPath]
})
expect(filterIndicator).toHaveTextContent('1')

setTableData({
...tableDataFixture,
filters: [firstFilterPath, secondFilterPath]
})
expect(filterIndicator).toHaveTextContent('2')
setTableData({
...tableDataFixture,
filters: [firstFilterPath, secondFilterPath]
})
expect(filterIndicator).toHaveTextContent('2')

setTableData({
...tableDataFixture,
filters: [firstFilterPath, secondFilterPath]
})
expect(filterIndicator).toHaveTextContent('2')
setTableData({
...tableDataFixture,
filters: [firstFilterPath, secondFilterPath]
})
expect(filterIndicator).toHaveTextContent('2')

setTableData({
...tableDataFixture,
filters: []
setTableData({
...tableDataFixture,
filters: []
})
expect(filterIndicator).toHaveTextContent('')
expect(tooltip).not.toHaveTextContent('Experiment')
jest.useRealTimers()
})
expect(filterIndicator).toHaveTextContent('')
expect(tooltip).not.toHaveTextContent('Experiment')
jest.useRealTimers()
})

it('should show a tooltip for the branches indicator', () => {
renderTable({
...tableDataFixture
})
jest.useFakeTimers()
const branchesIndicator = screen.getByLabelText('branches')
expect(branchesIndicator).toHaveTextContent('')
it('should show a tooltip for the branches indicator', () => {
renderTable({
...tableDataFixture
})
jest.useFakeTimers()
const branchesIndicator = screen.getByLabelText('branches')
expect(branchesIndicator).toHaveTextContent('')

expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()

fireEvent.mouseEnter(branchesIndicator)
advanceTimersByTime(1000)
fireEvent.mouseEnter(branchesIndicator)
advanceTimersByTime(1000)

const tooltip = screen.getByRole('tooltip')
const tooltip = screen.getByRole('tooltip')

expect(tooltip).toHaveTextContent('Select Branches')
jest.useRealTimers()
})
expect(tooltip).toHaveTextContent('Select Branches')
jest.useRealTimers()
})

it('should show an indicator for the number of branches selected', () => {
const branches = ['main', 'other', 'third']
it('should show an indicator for the number of branches selected', () => {
const branches = ['main', 'other', 'third']

let workspace
const rowsWithoutWorkspace = []
for (const row of tableDataFixture.rows) {
if (row.id !== EXPERIMENT_WORKSPACE_ID) {
rowsWithoutWorkspace.push(row)
continue
let workspace
const rowsWithoutWorkspace = []
for (const row of tableDataFixture.rows) {
if (row.id !== EXPERIMENT_WORKSPACE_ID) {
rowsWithoutWorkspace.push(row)
continue
}
workspace = row
}
workspace = row
}

const multipleBranches = {
...tableDataFixture,
branches,
hasData: true,
rows: [
workspace as Commit,
...rowsWithoutWorkspace.map(row => ({
...row,
branch: branches[0],
subRows: undefined
})),
...rowsWithoutWorkspace.map(row => ({
...row,
branch: branches[1],
subRows: undefined
})),
...rowsWithoutWorkspace.map(row => ({
...row,
branch: branches[2],
subRows: undefined
}))
]
}
const multipleBranches = {
...tableDataFixture,
branches,
hasData: true,
rows: [
workspace as Commit,
...rowsWithoutWorkspace.map(row => ({
...row,
branch: branches[0],
subRows: undefined
})),
...rowsWithoutWorkspace.map(row => ({
...row,
branch: branches[1],
subRows: undefined
})),
...rowsWithoutWorkspace.map(row => ({
...row,
branch: branches[2],
subRows: undefined
}))
]
}

renderTable(multipleBranches)
renderTable(multipleBranches)

const [indicator] = screen.getAllByLabelText('branches')
const [indicator] = screen.getAllByLabelText('branches')

expect(indicator).toHaveTextContent(`${branches.length - 1}`)
})
expect(indicator).toHaveTextContent(`${branches.length - 1}`)
})

it('should send a message to focus the relevant tree when clicked', () => {
renderTable()
mockPostMessage.mockClear()
fireEvent.click(screen.getByLabelText('sorts'))
expect(mockPostMessage).toHaveBeenCalledWith({
type: MessageFromWebviewType.FOCUS_SORTS_TREE
it('should send a message to focus the relevant tree when clicked', () => {
renderTable()
mockPostMessage.mockClear()
fireEvent.click(screen.getByLabelText('sorts'))
expect(mockPostMessage).toHaveBeenCalledWith({
type: MessageFromWebviewType.FOCUS_SORTS_TREE
})
mockPostMessage.mockClear()
fireEvent.click(screen.getByLabelText('filters'))
expect(mockPostMessage).toHaveBeenCalledWith({
type: MessageFromWebviewType.FOCUS_FILTERS_TREE
})

mockPostMessage.mockClear()
fireEvent.click(screen.getByLabelText('selected for plots'))
expect(mockPostMessage).toHaveBeenCalledWith({
type: MessageFromWebviewType.OPEN_PLOTS_WEBVIEW
})
})
mockPostMessage.mockClear()
fireEvent.click(screen.getByLabelText('filters'))
expect(mockPostMessage).toHaveBeenCalledWith({
type: MessageFromWebviewType.FOCUS_FILTERS_TREE

it('should show an indicator with the amount of displayed columns', () => {
renderTable({
...tableDataFixture
})
jest.useFakeTimers()
const columnsIndicator = screen.getByLabelText('columns')
expect(columnsIndicator).toHaveTextContent('22')

expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()

fireEvent.mouseEnter(columnsIndicator)
advanceTimersByTime(1000)
const tooltip = screen.getByRole('tooltip')

expect(tooltip).toHaveTextContent('Select Columns')

setTableData({
...tableDataFixture,
columns: tableDataFixture.columns.slice(1)
})

expect(columnsIndicator).toHaveTextContent('21')

setTableData({
...tableDataFixture,
columns: []
})

expect(columnsIndicator).toHaveTextContent('')

jest.useRealTimers()
})

mockPostMessage.mockClear()
fireEvent.click(screen.getByLabelText('selected for plots'))
expect(mockPostMessage).toHaveBeenCalledWith({
type: MessageFromWebviewType.OPEN_PLOTS_WEBVIEW
it('should send a message to select columns when the select columns icon is clicked', () => {
renderTable()
mockPostMessage.mockClear()
fireEvent.click(screen.getByLabelText('columns'))
expect(mockPostMessage).toHaveBeenCalledWith({
type: MessageFromWebviewType.SELECT_COLUMNS
})
})
})

Expand Down
28 changes: 24 additions & 4 deletions webview/src/experiments/components/table/Indicators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import {
focusFiltersTree,
focusSortsTree,
openPlotsWebview,
selectBranches
selectBranches,
selectColumns
} from '../../util/messages'
import { Icon } from '../../../shared/components/Icon'
import {
Filter,
GitMerge,
GraphScatter,
ListFilter,
SortPrecedence
} from '../../../shared/components/icons'
import { ExperimentsState } from '../../store'
Expand Down Expand Up @@ -72,21 +74,30 @@ export const Indicators = () => {
const filters = useSelector(
(state: ExperimentsState) => state.tableData.filters
)
const filtersCount = filters?.length

const sorts = useSelector((state: ExperimentsState) => state.tableData.sorts)
const sortsCount = sorts?.length

const selectedForPlotsCount = useSelector(
(state: ExperimentsState) => state.tableData.selectedForPlotsCount
)

const branchesSelected = useSelector(
(state: ExperimentsState) =>
Math.max(state.tableData.branches.filter(Boolean).length - 1, 0) // We always have one branch by default (the current one which is not selected) and undefined for the workspace
)

const { hasBranchesToSelect } = useSelector(
(state: ExperimentsState) => state.tableData
)

const sortsCount = sorts?.length
const filtersCount = filters?.length
const columnsSelected = useSelector(
(state: ExperimentsState) =>
state.tableData.columns.filter(({ hasChildren }) => !hasChildren).length
)
const hasColumns = useSelector(
(state: ExperimentsState) => state.tableData.hasColumns
)

return (
<div className={styles.tableIndicators}>
Expand Down Expand Up @@ -123,6 +134,15 @@ export const Indicators = () => {
>
<Icon width={16} height={16} icon={GitMerge} />
</Indicator>
<Indicator
count={columnsSelected}
aria-label="columns"
onClick={selectColumns}
tooltipContent="Select Columns"
disabled={!hasColumns}
>
<Icon width={16} height={16} icon={ListFilter} />
</Indicator>
</div>
)
}

0 comments on commit 07f8adb

Please sign in to comment.