Skip to content
This repository was archived by the owner on Jan 16, 2024. It is now read-only.

Moved Header from TableWidget #736

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
21 changes: 0 additions & 21 deletions src/components/widgets/TableWidget/TableWidget.less
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,3 @@
padding-right: 30px;
}
}

.filtersContainer {
:global {
.ant-select {
padding-top: 10px;
padding-right: 10px;
}

.ant-select-selection {
border: none;

&:focus, &:active{
box-shadow: none;
}

&__rendered {
margin-left: 0;
}
}
}
}
111 changes: 49 additions & 62 deletions src/components/widgets/TableWidget/TableWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React, { FunctionComponent } from 'react'
import React, { FunctionComponent, useCallback, useMemo } from 'react'
import { connect } from 'react-redux'
import { Dispatch } from 'redux'
import { Table } from 'antd'
import { ColumnProps, TableProps, TableRowSelection } from 'antd/es/table'
import ActionLink from '../../ui/ActionLink/ActionLink'
import { $do } from '../../../actions/actions'
import { Store } from '../../../interfaces/store'
import { PaginationMode, WidgetListField, WidgetTableMeta } from '../../../interfaces/widget'
Expand All @@ -20,11 +19,9 @@ import cn from 'classnames'
import Pagination from '../../ui/Pagination/Pagination'
import HierarchyTable from '../../../components/HierarchyTable/HierarchyTable'
import { BcFilter, FilterGroup } from '../../../interfaces/filters'
import { useTranslation } from 'react-i18next'
import FullHierarchyTable from '../../../components/FullHierarchyTable/FullHierarchyTable'
import { parseFilters } from '../../../utils/filters'
import Select from '../../ui/Select/Select'
import RowOperationsButton from '../../RowOperations/RowOperationsButton'
import Header from './components/Header'
import { useRowMenu } from '../../../hooks/useRowMenu'

type AdditionalAntdTableProps = Partial<Omit<TableProps<DataItem>, 'rowSelection'>>
Expand All @@ -44,6 +41,9 @@ export interface TableWidgetOwnProps extends AdditionalAntdTableProps {
export interface TableWidgetProps extends TableWidgetOwnProps {
data: DataItem[]
rowMetaFields: RowMetaField[]
/**
* @deprecated TODO: Remove 2.0 as it is never used
*/
limitBySelf: boolean
/**
* @deprecated TODO: Remove in 2.0 in favor of `widgetName`
Expand All @@ -69,7 +69,13 @@ export interface TableWidgetProps extends TableWidgetOwnProps {
* @deprecated TODO: Remove in 2.0.0 as it's moved to RowOperationsMenu
*/
metaInProgress?: boolean
/**
* @deprecated TODO: Remove 2.0 as it is never used
*/
filters: BcFilter[]
/**
* @deprecated TODO: Remove 2.0 as it is never used
*/
filterGroups: FilterGroup[]
/**
* @deprecated TODO: Remove 2.0 as it is never used
Expand All @@ -86,8 +92,17 @@ export interface TableWidgetProps extends TableWidgetOwnProps {
*/
onSelectRow?: (bcName: string, cursor: string) => void
onSelectCell: (cursor: string, widgetName: string, fieldKey: string) => void
/**
* @deprecated TODO: Remove 2.0 as it is never used
*/
onRemoveFilters: (bcName: string) => void
/**
* @deprecated TODO: Remove 2.0 as it is never used
*/
onApplyFilter: (bcName: string, filter: BcFilter, widgetName?: string) => void
/**
* @deprecated TODO: Remove 2.0 as it is never used
*/
onForceUpdate: (bcName: string) => void
}

Expand Down Expand Up @@ -141,24 +156,23 @@ export const TableWidget: FunctionComponent<TableWidgetProps> = props => {
}
}
const isAllowEdit = (props.allowEdit ?? true) && !props.meta.options?.readOnly
const { t } = useTranslation()

const processCellClick = React.useCallback(
const processCellClick = useCallback(
(recordId: string, fieldKey: string) => {
onSelectCell(recordId, widgetMetaName, fieldKey)
},
[onSelectCell, widgetMetaName]
)

const processedFields: WidgetListField[] = React.useMemo(
const processedFields: WidgetListField[] = useMemo(
() =>
fields.map(item => {
return item.type === FieldType.multivalue ? { ...item, type: FieldType.multivalueHover } : item
}),
[fields]
)

const columns: Array<ColumnProps<DataItem>> = React.useMemo(() => {
const columns: Array<ColumnProps<DataItem>> = useMemo(() => {
return processedFields
.filter(item => item.type !== FieldType.hidden && !item.hidden)
.map(item => {
Expand Down Expand Up @@ -217,7 +231,7 @@ export const TableWidget: FunctionComponent<TableWidgetProps> = props => {
selectedCell
])

const resultColumns = React.useMemo(() => {
const resultColumns = useMemo(() => {
const controlColumnsLeft: Array<ColumnProps<DataItem>> = []
const controlColumnsRight: Array<ColumnProps<DataItem>> = []
props.controlColumns?.map(item => {
Expand All @@ -226,61 +240,10 @@ export const TableWidget: FunctionComponent<TableWidgetProps> = props => {
return [...controlColumnsLeft, ...columns, ...controlColumnsRight]
}, [columns, props.controlColumns])

const [filterGroupName, setFilterGroupName] = React.useState(null)
const filtersExist = !!props.filters?.length

const handleShowAll = React.useCallback(() => {
onShowAll(widgetBcName, cursor, null, widgetName)
}, [onShowAll, widgetBcName, cursor, widgetName])

const handleRemoveFilters = React.useCallback(() => {
onRemoveFilters(widgetBcName)
onForceUpdate(widgetBcName)
}, [onRemoveFilters, onForceUpdate, widgetBcName])

const handleAddFilters = React.useMemo(() => {
return (value: string) => {
const filterGroup = filterGroups.find(item => item.name === value)
const parsedFilters = parseFilters(filterGroup.filters)
setFilterGroupName(filterGroup.name)
onRemoveFilters(widgetBcName)
parsedFilters.forEach(item => onApplyFilter(widgetBcName, item, widgetName))
onForceUpdate(widgetBcName)
}
}, [filterGroups, widgetBcName, widgetName, setFilterGroupName, onRemoveFilters, onApplyFilter, onForceUpdate])

React.useEffect(() => {
if (!filtersExist) {
setFilterGroupName(null)
}
}, [filtersExist])

const defaultHeader = React.useMemo(() => {
return (
<div className={styles.filtersContainer}>
{!!filterGroups?.length && (
<Select
value={filterGroupName ?? t('Show all').toString()}
onChange={handleAddFilters}
dropdownMatchSelectWidth={false}
>
{filterGroups.map(group => (
<Select.Option key={group.name} value={group.name}>
<span>{group.name}</span>
</Select.Option>
))}
</Select>
)}
{filtersExist && <ActionLink onClick={handleRemoveFilters}> {t('Clear all filters')} </ActionLink>}
{props.limitBySelf && <ActionLink onClick={handleShowAll}> {t('Show all records')} </ActionLink>}
</div>
)
}, [filterGroups, filterGroupName, filtersExist, props.limitBySelf, t, handleAddFilters, handleRemoveFilters, handleShowAll])

const [operationsRef, parentRef, onRow] = useRowMenu()
return (
<div className={styles.tableContainer} ref={parentRef}>
{props.header ?? defaultHeader}
{props.header ?? <Header bcName={widgetBcName} widgetName={widgetName} />}
<Table
className={cn(styles.table, { [styles.tableWithRowMenu]: props.showRowActions })}
columns={resultColumns}
Expand Down Expand Up @@ -311,7 +274,13 @@ function mapStateToProps(store: Store, ownProps: TableWidgetOwnProps) {
return {
data: store.data[ownProps.meta.bcName],
rowMetaFields: fields,
/**
* @deprecated
*/
limitBySelf,
/**
* @deprecated
*/
bcName,
/**
* @deprecated
Expand All @@ -324,7 +293,13 @@ function mapStateToProps(store: Store, ownProps: TableWidgetOwnProps) {
* @deprecated
*/
pendingDataItem: null as PendingDataItem,
/**
* @deprecated
*/
filters,
/**
* @deprecated
*/
filterGroups: bc?.filterGroups
}
}
Expand All @@ -334,19 +309,31 @@ function mapDispatchToProps(dispatch: Dispatch) {
onSelectCell: (cursor: string, widgetName: string, fieldKey: string) => {
dispatch($do.selectTableCellInit({ widgetName, rowId: cursor, fieldKey }))
},
/**
* @deprecated TODO: Remove in 2.0
*/
onShowAll: (bcName: string, cursor: string, route?: Route) => {
dispatch($do.showAllTableRecordsInit({ bcName, cursor }))
},
/**
* @deprecated TODO: Remove in 2.0
*/
onDrillDown: null as (widgetName: string, cursor: string, bcName: string, fieldKey: string) => void,
/**
* @deprecated TODO: Remove in 2.0
*/
onRemoveFilters: (bcName: string) => {
dispatch($do.bcRemoveAllFilters({ bcName }))
},
/**
* @deprecated TODO: Remove in 2.0
*/
onApplyFilter: (bcName: string, filter: BcFilter, widgetName?: string) => {
dispatch($do.bcAddFilter({ bcName, filter, widgetName }))
},
/**
* @deprecated TODO: Remove in 2.0
*/
onForceUpdate: (bcName: string) => {
dispatch($do.bcForceUpdate({ bcName }))
}
Expand Down
20 changes: 20 additions & 0 deletions src/components/widgets/TableWidget/components/Header.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.filtersContainer {
:global {
.ant-select {
padding-top: 10px;
padding-right: 10px;
}

.ant-select-selection {
border: none;

&:focus, &:active{
box-shadow: none;
}

&__rendered {
margin-left: 0;
}
}
}
}
112 changes: 112 additions & 0 deletions src/components/widgets/TableWidget/components/Header.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react'
import { mount, ReactWrapper } from 'enzyme'
import { Store } from 'redux'
import { Store as CoreStore } from '../../../../interfaces/store'
import { mockStore } from '../../../../tests/mockStore'
import * as redux from 'react-redux'
import { Provider } from 'react-redux'
import Header, { HeaderProps } from './Header'
import { FilterType } from '../../../../interfaces/filters'
import { ActionLink } from '../../../index'
import { initLocale } from '../../../../imports/i18n'
import i18n from 'i18next'
import Select from '../../../ui/Select/Select'

describe('TableWidget > Header test', () => {
let store: Store<CoreStore> = null
let wrapper: ReactWrapper = null

const dispatch = jest.fn()

beforeAll(() => {
initLocale('en', null)
store = mockStore()
})

beforeEach(() => {
jest.spyOn(redux, 'useDispatch').mockImplementation(() => {
return dispatch
})
})

afterEach(() => {
dispatch.mockClear()
jest.resetAllMocks()
})

function getMountWrapper() {
const restProps: HeaderProps = {
bcName: 'bcName',
widgetName: 'widgetName'
}

return mount(
<Provider store={store}>
<Header {...restProps} />
</Provider>
)
}

it('should render header', () => {
wrapper = getMountWrapper()

const headerComponent = wrapper.find(Header)
expect(headerComponent).toHaveLength(1)
})

it('header contain clearing button', () => {
store.getState().screen.filters.bcName = [
{
type: 'equalsOneOf' as FilterType,
value: ['Low', 'Middle'],
fieldName: 'importance',
viewName: 'clientlist',
widgetName: 'clientList'
}
]

wrapper = getMountWrapper()
const headerComponent = wrapper.find(Header)
const actionLinkComponent = headerComponent.find(ActionLink)

expect(actionLinkComponent).toHaveLength(1)
expect(actionLinkComponent.text().trim()).toBe(i18n.t('Clear all filters'))
})

it("header don't contain clearing button", () => {
store.getState().screen.filters.bcName = []

wrapper = getMountWrapper()
const headerComponent = wrapper.find(Header)
const actionLinkComponent = headerComponent.find(ActionLink)

expect(actionLinkComponent).toHaveLength(0)
})

it('header contain select for filter groups', () => {
store.getState().screen.bo.bc = {
bcName: {
name: 'bcName',
parentName: null,
url: '',
cursor: null,
filterGroups: [
{
name: 'Example PDQ 1',
filters: 'someField1.contains=123'
},
{
name: 'Example PDQ 2',
filters: 'someField1.contains=321&someField2.equalsOneOf=["Confirmed", "Canceled"]'
}
]
}
}

wrapper = getMountWrapper()
const headerComponent = wrapper.find(Header)
const selectComponent = headerComponent.find(Select)

expect(selectComponent).toHaveLength(1)
})
})
Loading