Skip to content

Commit

Permalink
Merge pull request #2539 from epam/rework_isAlwaysVisible_columns
Browse files Browse the repository at this point in the history
[DataTable]: reworked `isAwaysVisible` column configuration prop and isLocked prop
  • Loading branch information
AlekseyManetov authored Oct 9, 2024
2 parents 8d609fe + 8c6ef40 commit f7c6a07
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 30 deletions.
1 change: 1 addition & 0 deletions app/src/demo/tables/editableTable/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function getColumnsTableMode(columnsProps: ColumnsProps) {
caption: 'Name',
width: 300,
fix: 'left',
isLocked: true,
renderCell: (props) => (
<DataTableCell
{ ...props.rowLens.prop('name').toProps() }
Expand Down
3 changes: 2 additions & 1 deletion app/src/demo/tables/filteredTable/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const personColumns: DataColumnProps<Person, number>[] = [
width: 130,
fix: 'left',
isSortable: true,
isAlwaysVisible: true,
isLocked: true,
},
{
key: 'profileStatus',
Expand All @@ -26,6 +26,7 @@ export const personColumns: DataColumnProps<Person, number>[] = [
width: 100,
minWidth: 90,
isSortable: true,
isAlwaysVisible: true,
},
{
key: 'salary',
Expand Down
2 changes: 1 addition & 1 deletion app/src/demo/tables/masterDetailedTable/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const personColumns: DataColumnProps<Person, PersonTableRecordId[], DataQ
fix: 'left',
isSortable: true,
justifyContent: 'space-between',
isAlwaysVisible: true,
isLocked: true,
}, {
key: 'profileStatus',
caption: 'Profile Status',
Expand Down
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# 5.*.* - **.**.****

**What's New**
[DataTable]:
* [Breaking change]: reworked `isAwaysVisible` column configuration prop. Now it's not make column fixed by default and doesn't forbid to unpin or reorder, it's only disallow to hide this column from table. If you need previous behavior, please use `isLocked` prop.
* Added `isLocked` prop for column configuration. If `true` value provided, makes this column locked, which means that you can't hide, unpin or reorder this column. This column should always be pined.
* [PickerInput]:
* Added support of `minCharsToSearch` > 0 with `searchPosition = 'body'`.
* Added renderEmpty prop to render custom empty block for depends on various reasons.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ const mockAcceptDropParams = (params: TAcceptDropParams): TAcceptDropParamsAll =

describe('columnsConfigurationUtils', () => {
describe('canAcceptDrop', () => {
it('should not accept drop before isAlwaysVisible fixed left columns', () => {
it('should not accept drop before isLocked fixed left columns', () => {
const params = mockAcceptDropParams({
dstData: {
column: {
key: '1', fix: 'left', caption: '1', isAlwaysVisible: true, width: 1,
key: '1', fix: 'left', caption: '1', isLocked: true, width: 1,
},
columnConfig: { width: 1, isVisible: true, order: 'a' },
},
Expand All @@ -68,18 +68,18 @@ describe('columnsConfigurationUtils', () => {
columnConfig: { width: 2, isVisible: true, order: 'b' },
},
});
const result = canAcceptDrop(params, { key: '100500', fix: 'left', isAlwaysVisible: true, width: 0 }); // Try to drop between 2 isAlwaysVisible columns
const result = canAcceptDrop(params, { key: '100500', fix: 'left', isLocked: true, width: 0 }); // Try to drop between 2 isLocked columns
expect(result).toEqual({});

const result2 = canAcceptDrop(params, { key: '100500', width: 0 }); // Try to drop at last isAlwaysVisible columns
const result2 = canAcceptDrop(params, { key: '100500', width: 0 }); // Try to drop at last isLocked columns
expect(result2).toEqual({ bottom: true });
});

it('should not accept drop after isAlwaysVisible fixed right columns', () => {
it('should not accept drop after isLocked fixed right columns', () => {
const params = mockAcceptDropParams({
dstData: {
column: {
key: '1', fix: 'right', caption: '1', isAlwaysVisible: true, width: 1,
key: '1', fix: 'right', caption: '1', isLocked: true, width: 1,
},
columnConfig: { width: 1, isVisible: true, order: 'a' },
},
Expand All @@ -90,12 +90,31 @@ describe('columnsConfigurationUtils', () => {
columnConfig: { width: 2, isVisible: true, order: 'b' },
},
});
const result = canAcceptDrop(params, { key: '100500', width: 0 }, { key: '100501', fix: 'right', isAlwaysVisible: true, width: 0 }); // Try to drop between 2 isAlwaysVisible columns
const result = canAcceptDrop(params, { key: '100500', width: 0 }, { key: '100501', fix: 'right', isLocked: true, width: 0 }); // Try to drop between 2 isLocked columns
expect(result).toEqual({});

const result2 = canAcceptDrop(params, { key: '100500', width: 0 }); // Try to drop at first isAlwaysVisible columns
const result2 = canAcceptDrop(params, { key: '100500', width: 0 }); // Try to drop at first isLocked columns
expect(result2).toEqual({ top: true });
});

it('should not accept drop for isAlwaysVisible column in hidden section', () => {
const params = mockAcceptDropParams({
dstData: {
column: {
key: '1', fix: 'right', caption: '1', width: 1,
},
columnConfig: { width: 1, isVisible: false, order: 'a' },
},
srcData: {
column: {
key: '2', caption: '2', width: 2, isAlwaysVisible: true,
},
columnConfig: { width: 2, isVisible: true, order: 'b' },
},
});
const result = canAcceptDrop(params);
expect(result).toEqual({});
});
});
describe('sortColumnsAndAddGroupKey', () => {
it('should sort columns by "order" and should add "groupKey" attribute', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,29 @@ import React from 'react';
import { AcceptDropParams, ColumnsConfig, DataColumnProps, DropPosition, getOrderBetween, IColumnConfig, orderBy } from '@epam/uui-core';
import { ColumnsConfigurationRowProps, DndDataType, GroupedColumnsType, GroupedDataColumnProps } from './types';

export function isColumnAlwaysPinned(column: DataColumnProps) {
return Boolean(column?.isAlwaysVisible);
export function isColumnLocked(column: DataColumnProps) {
return Boolean(column?.isLocked);
}

export function canAcceptDrop(props: AcceptDropParams<DndDataType, DndDataType>, nextColumn?: DataColumnProps, prevColumn?: DataColumnProps) {
const { dstData } = props;
const { dstData, srcData } = props;

if (isColumnAlwaysPinned(dstData.column)) {
if (dstData.column.fix === 'left' && !isColumnAlwaysPinned(nextColumn)) { // If user try to drop column at the last isAlwaysVisible column. Allow to drop only to the end of the fixed list.
if (isColumnLocked(dstData.column)) {
if (dstData.column.fix === 'left' && !isColumnLocked(nextColumn)) { // If user try to drop column at the last isAlwaysVisible column. Allow to drop only to the end of the fixed list.
return { bottom: true };
}

if (dstData.column.fix === 'right' && !isColumnAlwaysPinned(prevColumn)) { // If user try to drop column at the first isAlwaysVisible. Allow to drop only to the start of the fixed list
if (dstData.column.fix === 'right' && !isColumnLocked(prevColumn)) { // If user try to drop column at the first isAlwaysVisible. Allow to drop only to the start of the fixed list
return { top: true };
}

return {}; // Shouldn't drop between 2 isAlwaysVisible columns
}

if (srcData.column.isAlwaysVisible && dstData.columnConfig.isVisible === false) {
return {}; // We shouldn't move isAlwaysVisible column into 'Hidden from table' group
}

return { top: true, bottom: true };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import {
canAcceptDrop,
isColumnAlwaysHiddenInTheConfigurationModal,
isColumnAlwaysPinned,
isColumnLocked,
} from '../columnsConfigurationUtils';
import { DndDataType, GroupedDataColumnProps, ColumnsConfigurationRowProps, TColumnPinPosition } from '../types';
import { groupAndFilterSortedColumns, sortColumnsAndAddGroupKey } from '../columnsConfigurationUtils';
Expand Down Expand Up @@ -75,7 +75,7 @@ export function useColumnsConfiguration(props: UseColumnsConfigurationProps<any,
};
});
};
const isPinnedAlways = isColumnAlwaysPinned(column);
const isPinnedAlways = isColumnLocked(column);
const fix = columnConfig.fix || (isPinnedAlways ? 'left' : undefined);
return {
...column,
Expand Down
2 changes: 1 addition & 1 deletion uui-core/src/helpers/applyColumnsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const getColumnsConfig = <TItem, TId>(columns: DataColumnProps<TItem, TId

resultConfig[column.key] = {
width: column.width,
fix: column.fix ?? (column.isAlwaysVisible ? 'left' : undefined),
fix: column.fix ?? (column.isLocked ? 'left' : undefined),
isVisible: !column.isHiddenByDefault,
order: order,
};
Expand Down
9 changes: 6 additions & 3 deletions uui-core/src/types/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,14 @@ export interface DataColumnProps<TItem = any, TId = any, TFilter = any> extends
*/
isSortable?: boolean;

/** Pass true to make this column always visible and forbid to hide it from columns config dialog */
isAlwaysVisible?: boolean;

/** Makes this column locked, which means that you can't hide, unpin or reorder this column. Usually applicable for such column without which table because useless.
* Note, that isAlwaysVisible column should be always fixed to any side of the table, if you didn't specify `column.fix` prop for such column, 'left' value will be used by default.
* Also, if you have a few isAlwaysVisible columns, it's necessary to place it together in the start or end(depends on `fix` prop) of columns array.
* Note, that isLocked column should be always fixed to any side of the table, if you didn't specify `column.fix` prop for such column, 'left' value will be used by default.
* Also, if you have a few isLocked columns, it's necessary to place it together in the start or end(depends on `fix` prop) of columns array.
* */
isAlwaysVisible?: boolean;
isLocked?: boolean;

/** Makes column hidden by default. User can turn it on later, via ColumnsConfiguration */
isHiddenByDefault?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const ColumnRow = React.memo(function ColumnRow(props: ColumnRowProps<any
label={ props.renderItem ? props.renderItem(props.column) : column.caption }
value={ isVisible }
onValueChange={ toggleVisibility }
isReadonly={ column.isAlwaysVisible }
isReadonly={ column.isAlwaysVisible || column.isLocked }
cx={ css.checkbox }
/>
<FlexRow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const mockColumns: DataColumnProps[] = [
caption: 'ID',
render: (product: any) => <div>{product}</div>,
isSortable: true,
isAlwaysVisible: true,
isLocked: true,
grow: 0,
width: 96,
}, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,77 @@ exports[`ColumnsConfigurationModal should be rendered correctly 1`] = `
</button>
</div>
</div>
</div>
</div>
</div>
<div
className="uui-flex-row root hDivider container align-items-center"
style={
Object {
"columnGap": undefined,
"rowGap": undefined,
}
}
/>
<div
aria-expanded={true}
className="uui-accordion-container container uui-opened subgroupAccordion"
>
<div
className="uui-accordion-toggler uui-opened"
onClick={[Function]}
onKeyDown={[Function]}
tabIndex={0}
>
<div
className="uui-accordion-toggle-container"
>
<div
className="uui-flex-row root rowWrapper container align-items-top"
className="uui-flex-row root uui-size-36 subgroup container align-items-center"
style={
Object {
"columnGap": undefined,
"rowGap": undefined,
}
}
>
<div
className="container uui-icon uui-enabled"
style={Object {}}
>
<svg
className=""
height="18"
width="18"
/>
</div>
<div
className="root uui-text uui-size-none uui-color-tertiary uui-font-weight-400 uui-font-style-normal uui-typography subgroupTitle container"
>
Not pinned
</div>
</div>
<div
className="container uui-icon uui-enabled arrow"
style={Object {}}
/>
</div>
</div>
<div
className="uui-accordion-body"
role="region"
>
<div
className="uui-flex-row root uui-size-30 groupItems container align-items-center"
style={
Object {
"columnGap": undefined,
"rowGap": undefined,
}
}
>
<div
className="uui-flex-row root rowWrapper notPinned container align-items-top"
onPointerEnter={[Function]}
onPointerLeave={[Function]}
onPointerMove={[Function]}
Expand All @@ -338,11 +407,12 @@ exports[`ColumnsConfigurationModal should be rendered correctly 1`] = `
}
>
<div
className="dragHandle dndDisabled container uui-drag-handle uui-disabled"
className="dragHandle container uui-drag-handle"
onPointerDown={[Function]}
onTouchStart={[Function]}
>
<div
className="container uui-icon uui-disabled"
className="container uui-icon uui-enabled"
style={Object {}}
>
<svg
Expand Down Expand Up @@ -389,9 +459,26 @@ exports[`ColumnsConfigurationModal should be rendered correctly 1`] = `
}
>
<button
aria-disabled={true}
className="uui-button-box uui-disabled container uui-icon_button uui-color-primary root pinTogglerIcon"
tabIndex={-1}
aria-disabled={false}
className="uui-button-box uui-enabled -clickable container uui-icon_button uui-color-neutral root pinTogglerIcon"
onClick={[Function]}
tabIndex={0}
type="button"
>
<div
className="container uui-icon uui-enabled"
style={Object {}}
>
<svg
className=""
/>
</div>
</button>
<button
aria-disabled={false}
className="uui-button-box uui-enabled -clickable container uui-icon_button uui-color-neutral root pinTogglerIcon"
onClick={[Function]}
tabIndex={0}
type="button"
>
<div
Expand Down

0 comments on commit f7c6a07

Please sign in to comment.