Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/contexts/ColumnParametersContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,3 @@ export interface ColumnParameters extends ColumnConfig, Pick<ColumnDescriptor, '
*/
type ColumnParametersContextType = ColumnParameters[]
export const ColumnParametersContext = createContext<ColumnParametersContextType>([])

/**
* A set of the names of the sortable columns. Used to check if a column is sortable, and to provide the toggle function in the OrderByContext.
*/
type SortableColumnsContextType = Set<string>
export const SortableColumnsContext = createContext<SortableColumnsContextType>(new Set())
5 changes: 5 additions & 0 deletions src/contexts/DataContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ import type { ColumnDescriptor, DataFrame } from '../helpers/dataframe/types.js'
*/
export type DataFrameMethods = Pick<DataFrame, 'getRowNumber' | 'getCell' | 'fetch'>
export type DataFrameWithoutMethods = Omit<DataFrame, 'getRowNumber' | 'getCell' | 'fetch'>
/**
* A set of the names of the sortable columns. Used to check if a column is sortable, and to provide the toggle function in the OrderByContext.
*/
type SortableColumnsContextType = Set<string>

Comment thread
severo marked this conversation as resolved.
Outdated
export const DataVersionContext = createContext<number>(0)
export const NumRowsContext = createContext<number>(0)
export const ColumnDescriptorsContext = createContext<Pick<ColumnDescriptor, 'name' | 'sortable'>[]>([])
export const NumColumnsContext = createContext<number>(0)
export const SortableColumnsContext = createContext<SortableColumnsContextType>(new Set())
export const ExclusiveSortContext = createContext<boolean>(false)
export const DataFrameMethodsContext = createContext<DataFrameMethods>({
getRowNumber: () => undefined,
Expand Down
11 changes: 2 additions & 9 deletions src/providers/ColumnParametersProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ReactNode, useContext, useMemo } from 'react'

import { type ColumnParameters, ColumnParametersContext, SortableColumnsContext } from '../contexts/ColumnParametersContext.js'
import { type ColumnParameters, ColumnParametersContext } from '../contexts/ColumnParametersContext.js'
import { ColumnDescriptorsContext } from '../contexts/DataContext.js'
import type { HighTableProps } from '../types.js'

Expand All @@ -17,11 +17,6 @@ type Props = Pick<HighTableProps, 'columnConfiguration'> & {
export function ColumnParametersProvider({ columnConfiguration, children }: Props) {
const columnDescriptors = useContext(ColumnDescriptorsContext)

// A column is sortable iif it's marked as sortable in the column descriptors from the data frame. The user configuration can't change that.
const sortableColumns = useMemo(() => {
return new Set(columnDescriptors.filter(({ sortable }) => sortable).map(({ name }) => name))
}, [columnDescriptors])

const columnParameters = useMemo(() => {
const inHeader = new Set(columnDescriptors.map(c => c.name))

Expand All @@ -47,9 +42,7 @@ export function ColumnParametersProvider({ columnConfiguration, children }: Prop

return (
<ColumnParametersContext.Provider value={columnParameters}>
<SortableColumnsContext.Provider value={sortableColumns}>
{children}
</SortableColumnsContext.Provider>
{children}
</ColumnParametersContext.Provider>
)
}
14 changes: 10 additions & 4 deletions src/providers/DataProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type ReactNode, useEffect, useState } from 'react'
import { type ReactNode, useEffect, useMemo, useState } from 'react'

import type { DataFrameWithoutMethods } from '../contexts/DataContext.js'
import { ColumnDescriptorsContext, DataFrameMethodsContext, DataKeyContext, DataVersionContext, ExclusiveSortContext, NumColumnsContext, NumRowsContext } from '../contexts/DataContext.js'
import { ColumnDescriptorsContext, DataFrameMethodsContext, DataKeyContext, DataVersionContext, ExclusiveSortContext, NumColumnsContext, NumRowsContext, SortableColumnsContext } from '../contexts/DataContext.js'
import type { HighTableProps } from '../types.js'

// Assign stable numeric ids to data instances without triggering state
Expand Down Expand Up @@ -63,9 +63,13 @@ function KeyedDataProvider({ children, data }: KeyedDataProviderProps) {

// Some dataframe properties are expected to be stable for a given data frame.
// We keep their initial value, no setter.
const [exclusiveSort] = useState(() => data.exclusiveSort === true)
const [columnDescriptors] = useState(() => data.columnDescriptors.map(({ name, sortable }) => ({ name, sortable })))
const numColumns = columnDescriptors.length
const [exclusiveSort] = useState(() => data.exclusiveSort === true)
// A column is sortable iif it's marked as sortable in the column descriptors from the data frame. The user configuration can't change that.
Comment thread
severo marked this conversation as resolved.
Outdated
const sortableColumns = useMemo(() => {
return new Set(columnDescriptors.filter(({ sortable }) => sortable).map(({ name }) => name))
}, [columnDescriptors])
Comment thread
severo marked this conversation as resolved.
Outdated

// Synchronize version and numRows with data frame events (external system - useEffect is needed)
useEffect(() => {
Expand All @@ -92,7 +96,9 @@ function KeyedDataProvider({ children, data }: KeyedDataProviderProps) {
<NumColumnsContext.Provider value={numColumns}>
<ExclusiveSortContext.Provider value={exclusiveSort}>
<NumRowsContext.Provider value={numRows}>
{children}
<SortableColumnsContext.Provider value={sortableColumns}>
{children}
</SortableColumnsContext.Provider>
</NumRowsContext.Provider>
</ExclusiveSortContext.Provider>
</NumColumnsContext.Provider>
Expand Down
3 changes: 1 addition & 2 deletions src/providers/OrderByProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { type ReactNode, useContext, useMemo } from 'react'

import { SortableColumnsContext } from '../contexts/ColumnParametersContext.js'
import { ExclusiveSortContext } from '../contexts/DataContext.js'
import { ExclusiveSortContext, SortableColumnsContext } from '../contexts/DataContext.js'
import { OrderByContext, SortInfoAndActionsByColumnContext } from '../contexts/OrderByContext.js'
import { type OrderBy, toggleColumn, toggleColumnExclusive } from '../helpers/sort.js'
import { useInputState } from '../hooks/useInputState.js'
Expand Down
35 changes: 1 addition & 34 deletions test/providers/ColumnParametersProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@ import { render } from '@testing-library/react'
import { useContext } from 'react'
import { describe, expect, it } from 'vitest'

import { ColumnParametersContext, SortableColumnsContext } from '../../src/contexts/ColumnParametersContext.js'
import { ColumnParametersContext } from '../../src/contexts/ColumnParametersContext.js'
import { ColumnDescriptorsContext } from '../../src/contexts/DataContext.js'
import type { ColumnConfiguration } from '../../src/helpers/columnConfiguration.js'
import { ColumnParametersProvider } from '../../src/providers/ColumnParametersProvider.js'

function TestComponent() {
const columnParameters = useContext(ColumnParametersContext)
const sortableColumns = useContext(SortableColumnsContext)
return (
<div>
<span data-testid="column-parameters">{JSON.stringify(columnParameters)}</span>
<span data-testid="sortable-columns">{JSON.stringify(Array.from(sortableColumns))}</span>
</div>
)
}
Expand All @@ -35,7 +33,6 @@ describe('ColumnParametersProvider', () => {
{ name: 'name', index: 1 },
{ name: 'status', index: 2 },
]))
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify([]))
})

it('merges columnConfiguration props into parameters', () => {
Expand All @@ -58,7 +55,6 @@ describe('ColumnParametersProvider', () => {
{ name: 'name', index: 1, headerComponent },
{ name: 'status', index: 2 },
]))
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify([]))
})

it('includes minWidth in column configuration', () => {
Expand All @@ -79,34 +75,6 @@ describe('ColumnParametersProvider', () => {
{ name: 'id', index: 0 },
{ name: 'name', index: 1, minWidth: 150 },
]))
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify([]))
})

it('uses dataframe column descriptor sortable value', () => {
const columnDescriptors = [
{ name: 'id' },
{ name: 'name', sortable: true },
{ name: 'status' },
]
const headerComponent = <strong>Name</strong>
const columnConfiguration: ColumnConfiguration = {
name: { headerComponent },
}

const { getByTestId } = render(
<ColumnDescriptorsContext.Provider value={columnDescriptors}>
<ColumnParametersProvider columnConfiguration={columnConfiguration}>
<TestComponent />
</ColumnParametersProvider>
</ColumnDescriptorsContext.Provider>
)

expect(getByTestId('column-parameters').textContent).toBe(JSON.stringify([
{ name: 'id', index: 0 },
{ name: 'name', index: 1, headerComponent },
{ name: 'status', index: 2 },
]))
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify(['name']))
})

it('ignores configuration keys that are not in DataFrame.columnDescriptors', () => {
Expand All @@ -127,6 +95,5 @@ describe('ColumnParametersProvider', () => {
expect(getByTestId('column-parameters').textContent).toBe(JSON.stringify([
{ name: 'id', index: 0, width: 50 },
]))
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify([]))
})
})
20 changes: 19 additions & 1 deletion test/providers/DataProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { render } from '@testing-library/react'
import { act, useContext } from 'react'
import { describe, expect, it, vi } from 'vitest'

import { ColumnDescriptorsContext, DataFrameMethodsContext, DataKeyContext, DataVersionContext, ExclusiveSortContext, NumColumnsContext, NumRowsContext } from '../../src/contexts/DataContext.js'
import { ColumnDescriptorsContext, DataFrameMethodsContext, DataKeyContext, DataVersionContext, ExclusiveSortContext, NumColumnsContext, NumRowsContext, SortableColumnsContext } from '../../src/contexts/DataContext.js'
import type { DataFrame, DataFrameEvents } from '../../src/helpers/dataframe/index.js'
import { arrayDataFrame } from '../../src/helpers/dataframe/index.js'
import { createEventTarget } from '../../src/helpers/typedEventTarget.js'
Expand All @@ -14,6 +14,7 @@ function DisplayComponent() {
const numRows = useContext(NumRowsContext)
const columnDescriptors = useContext(ColumnDescriptorsContext)
const numColumns = useContext(NumColumnsContext)
const sortableColumns = useContext(SortableColumnsContext)
const exclusiveSort = useContext(ExclusiveSortContext) ? 'true' : 'false'
const dataFrameMethods = useContext(DataFrameMethodsContext)

Expand All @@ -24,6 +25,7 @@ function DisplayComponent() {
<span data-testid="num-rows">{numRows}</span>
<span data-testid="column-descriptors">{JSON.stringify(columnDescriptors)}</span>
<span data-testid="num-columns">{numColumns}</span>
<span data-testid="sortable-columns">{JSON.stringify(Array.from(sortableColumns))}</span>
<span data-testid="exclusive-sort">{exclusiveSort}</span>
<button
data-testid="get-cell"
Expand Down Expand Up @@ -67,7 +69,9 @@ describe('DataProvider', () => {
const { getByTestId } = render(<TestComponent data={data} />)
expect(getByTestId('data-version').textContent).toBe('0')
expect(getByTestId('num-rows').textContent).toBe(data.numRows.toString())
expect(getByTestId('column-descriptors').textContent).toBe(JSON.stringify(data.columnDescriptors))
Comment thread
severo marked this conversation as resolved.
Outdated
expect(getByTestId('num-columns').textContent).toBe(data.columnDescriptors.length.toString())
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify([]))
expect(getByTestId('exclusive-sort').textContent).toBe('false')
})

Expand Down Expand Up @@ -217,6 +221,20 @@ describe('DataProvider', () => {
rerender(<TestComponent data={data} />)
expect(getByTestId('num-columns').textContent).toBe('2')
})
it('should provide the initial sortable columns based on column descriptors', () => {
const data = arrayDataFrame([{ a: 1, b: 2 }, { a: 3, b: 4 }])
if (data.columnDescriptors[0] === undefined || data.columnDescriptors[1] === undefined) {
throw new Error('Not enough column descriptors')
}
data.columnDescriptors[0].sortable = true
const { getByTestId, rerender } = render(<TestComponent data={data} />)
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify(['a']))
// Change the sortable property of the column descriptors in the data frame
data.columnDescriptors[1].sortable = true
// force a re-render without changing the data frame instance
rerender(<TestComponent data={data} />)
expect(getByTestId('sortable-columns').textContent).toBe(JSON.stringify(['a']))
})
it('should provide the initial exclusiveSort value', () => {
const data = arrayDataFrame([{ a: 1, b: 2 }, { a: 3, b: 4 }])
data.exclusiveSort = true
Expand Down
3 changes: 1 addition & 2 deletions test/providers/OrderByProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { fireEvent, render } from '@testing-library/react'
import { act, useContext } from 'react'
import { describe, expect, it, vi } from 'vitest'

import { SortableColumnsContext } from '../../src/contexts/ColumnParametersContext.js'
import { ExclusiveSortContext } from '../../src/contexts/DataContext.js'
import { ExclusiveSortContext, SortableColumnsContext } from '../../src/contexts/DataContext.js'
import { OrderByContext, SortInfoAndActionsByColumnContext } from '../../src/contexts/OrderByContext.js'
import { OrderByProvider } from '../../src/providers/OrderByProvider.js'

Expand Down