From 4208991f198ae2359c739dcbe2798c9f47aea55b Mon Sep 17 00:00:00 2001 From: MarcusNotheis Date: Thu, 26 Mar 2020 17:47:30 +0100 Subject: [PATCH 1/2] feat(AnalyticalTable): Add Highlight Column Closes #312 --- .../defaults/Column/Expandable.tsx | 4 +- .../AnalyticalTable/demo/demo.stories.tsx | 2 + .../AnalyticalTable/demo/generateData.ts | 8 ++- .../hooks/useColumnsDependencies.ts | 5 +- .../hooks/useDynamicColumnWidths.ts | 2 +- .../AnalyticalTable/hooks/useRowHighlight.tsx | 67 +++++++++++++++++++ .../hooks/useRowSelectionColumn.tsx | 8 +++ .../hooks/useTableCellStyling.ts | 4 ++ .../src/components/AnalyticalTable/index.tsx | 12 +++- 9 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 packages/main/src/components/AnalyticalTable/hooks/useRowHighlight.tsx diff --git a/packages/main/src/components/AnalyticalTable/defaults/Column/Expandable.tsx b/packages/main/src/components/AnalyticalTable/defaults/Column/Expandable.tsx index 5e8dbe3d093..a3621d7c3d0 100644 --- a/packages/main/src/components/AnalyticalTable/defaults/Column/Expandable.tsx +++ b/packages/main/src/components/AnalyticalTable/defaults/Column/Expandable.tsx @@ -38,7 +38,7 @@ export const Expandable = (props) => { const tableColumns = selectionMode === TableSelectionMode.NONE || noSelectionColumn ? columns - : columns.filter(({ id }) => id !== '__ui5wcr__internal_selection_column'); + : columns.filter(({ id }) => id !== '__ui5wcr__internal_selection_column' && id !== '__ui5wcr__internal_highlight_column'); const columnIndex = tableColumns.findIndex((col) => col.id === column.id); @@ -52,7 +52,7 @@ export const Expandable = (props) => { paddingLeft }; - if (column.id === '__ui5wcr__internal_selection_column') { + if (column.id === '__ui5wcr__internal_selection_column' || column.id === '__ui5wcr__internal_highlight_column') { return cell.render('Cell'); } diff --git a/packages/main/src/components/AnalyticalTable/demo/demo.stories.tsx b/packages/main/src/components/AnalyticalTable/demo/demo.stories.tsx index 89f32f7421e..d5b6aff9f5b 100644 --- a/packages/main/src/components/AnalyticalTable/demo/demo.stories.tsx +++ b/packages/main/src/components/AnalyticalTable/demo/demo.stories.tsx @@ -88,6 +88,8 @@ export const defaultTable = () => { selectedRowIds={object('selectedRowIds', { 3: true })} onColumnsReordered={action('onColumnsReordered')} noSelectionColumn={boolean('noSelectionColumn', false)} + withRowHighlight={boolean('withRowHighlight', true)} + highlightField={text('highlightField', 'status')} /> ); diff --git a/packages/main/src/components/AnalyticalTable/demo/generateData.ts b/packages/main/src/components/AnalyticalTable/demo/generateData.ts index 644b5d416eb..9325d5a7cc1 100644 --- a/packages/main/src/components/AnalyticalTable/demo/generateData.ts +++ b/packages/main/src/components/AnalyticalTable/demo/generateData.ts @@ -1,3 +1,5 @@ +import { ValueState } from "@ui5/webcomponents-react/lib/ValueState"; + const getRandomArrayEntry = (array) => array[Math.floor(Math.random() * array.length)]; const getRandomNumber = (min, max) => Math.floor(Math.random() * (max - min) + min); @@ -35,7 +37,8 @@ const newEntry = () => { friend: { name: getRandomName(), age: getRandomNumber(18, 65) - } + }, + status: [ValueState.None, ValueState.Information, ValueState.Success, ValueState.Warning, ValueState.Error][Math.floor(Math.random() * 4)] }; }; @@ -59,7 +62,8 @@ const makeEntry = () => ({ friend: { name: getRandomName(), age: getRandomNumber(18, 65) - } + }, + status: [ValueState.None, ValueState.Information, ValueState.Success, ValueState.Warning, ValueState.Error][Math.floor(Math.random() * 4)] }); const generateData = (numEntries, isTree = false) => { diff --git a/packages/main/src/components/AnalyticalTable/hooks/useColumnsDependencies.ts b/packages/main/src/components/AnalyticalTable/hooks/useColumnsDependencies.ts index 5ad044fda7c..935eab5ace0 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useColumnsDependencies.ts +++ b/packages/main/src/components/AnalyticalTable/hooks/useColumnsDependencies.ts @@ -1,11 +1,10 @@ export const useColumnsDependencies = (hooks) => { hooks.columnsDeps.push((deps, { instance: { state, webComponentsReactProperties } }) => { return [ + ...deps, state.tableClientWidth, webComponentsReactProperties.scaleWidthMode, - webComponentsReactProperties.loading, - webComponentsReactProperties.selectionMode, - webComponentsReactProperties.noSelectionColumn + webComponentsReactProperties.loading ]; }); }; diff --git a/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts b/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts index 26eb17d7552..ba8b3b8f628 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts +++ b/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts @@ -61,7 +61,7 @@ export const useDynamicColumnWidths = (hooks) => { const rowSample = rows.slice(0, ROW_SAMPLE_SIZE); const columnMeta = visibleColumns.reduce((acc, column) => { - if (column.id === '__ui5wcr__internal_selection_column') { + if (column.id === '__ui5wcr__internal_selection_column' || column.id === '__ui5wcr__internal_highlight_column') { acc[column.accessor] = { minHeaderWidth: column.width, fullWidth: column.width, diff --git a/packages/main/src/components/AnalyticalTable/hooks/useRowHighlight.tsx b/packages/main/src/components/AnalyticalTable/hooks/useRowHighlight.tsx new file mode 100644 index 00000000000..f3cac874d74 --- /dev/null +++ b/packages/main/src/components/AnalyticalTable/hooks/useRowHighlight.tsx @@ -0,0 +1,67 @@ +import { ThemingParameters } from '@ui5/webcomponents-react-base/lib/ThemingParameters'; +import { ValueState } from '@ui5/webcomponents-react/lib/ValueState'; +import React from 'react'; + +const baseStyles = { + width: '100%', + height: '100%' +}; + +const StyleMap = new Map(); +StyleMap.set(ValueState.None, baseStyles); +StyleMap.set(ValueState.Success, { ...baseStyles, backgroundColor: ThemingParameters.sapSuccessColor }); +StyleMap.set(ValueState.Warning, { ...baseStyles, backgroundColor: ThemingParameters.sapWarningColor }); +StyleMap.set(ValueState.Error, { ...baseStyles, backgroundColor: ThemingParameters.sapErrorColor }); +StyleMap.set(ValueState.Information, { ...baseStyles, backgroundColor: ThemingParameters.sapInformationColor }); + +export const useRowHighlight = (hooks) => { + hooks.columns.push((columns, { instance }) => { + const { withRowHighlight, highlightField } = instance.webComponentsReactProperties; + + if (!withRowHighlight) { + return columns; + } + + return [ + { + id: '__ui5wcr__internal_highlight_column', + accessor: highlightField, + sortable: false, + groupable: false, + filterable: false, + disableResizing: true, + canReorder: false, + width: 6, + minWidth: 6, + maxWidth: 6, + // eslint-disable-next-line react/display-name + Header: () =>
, + // eslint-disable-next-line react/display-name,react/prop-types + Cell: ({ cell: { value } }) => { + return
; + } + }, + ...columns + ]; + }); + + hooks.columnsDeps.push((deps, { instance: { webComponentsReactProperties } }) => { + return [...deps, webComponentsReactProperties.withRowHighlight, webComponentsReactProperties.highlightField]; + }); + + hooks.visibleColumnsDeps.push((deps, { instance }) => [ + ...deps, + instance.webComponentsReactProperties.withRowHighlight + ]); + + hooks.visibleColumns.push((columns, { instance: { webComponentsReactProperties } }) => { + if (!webComponentsReactProperties.withRowHighlight) { + return columns.filter(({ id }) => id !== '__ui5wcr__internal_highlight_column'); + } + + const highlightColumn = columns.find(({ id }) => id === '__ui5wcr__internal_highlight_column'); + return [highlightColumn, ...columns.filter(({ id }) => id !== '__ui5wcr__internal_highlight_column')]; + }); +}; + +useRowHighlight.pluginName = 'useRowHighlight'; diff --git a/packages/main/src/components/AnalyticalTable/hooks/useRowSelectionColumn.tsx b/packages/main/src/components/AnalyticalTable/hooks/useRowSelectionColumn.tsx index df634bebcc0..46edea78dae 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useRowSelectionColumn.tsx +++ b/packages/main/src/components/AnalyticalTable/hooks/useRowSelectionColumn.tsx @@ -76,6 +76,14 @@ export const useRowSelectionColumn: PluginHook<{}> = (hooks) => { ]; }); + hooks.columnsDeps.push((deps, { instance: { state, webComponentsReactProperties } }) => { + return [ + ...deps, + webComponentsReactProperties.selectionMode, + webComponentsReactProperties.noSelectionColumn + ]; + }); + hooks.visibleColumnsDeps.push((deps, { instance }) => [ ...deps, instance.webComponentsReactProperties.noSelectionColumn, diff --git a/packages/main/src/components/AnalyticalTable/hooks/useTableCellStyling.ts b/packages/main/src/components/AnalyticalTable/hooks/useTableCellStyling.ts index 64b980b830d..f222de3df27 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useTableCellStyling.ts +++ b/packages/main/src/components/AnalyticalTable/hooks/useTableCellStyling.ts @@ -47,6 +47,10 @@ export const useTableCellStyling: PluginHook<{}> = (hooks) => { className += ` ${column.className}`; } + if (column.id === '__ui5wcr__internal_highlight_column') { + style.padding = 0; + } + return { ...cellProps, className, diff --git a/packages/main/src/components/AnalyticalTable/index.tsx b/packages/main/src/components/AnalyticalTable/index.tsx index d5a797f1c21..ded40d22f7b 100644 --- a/packages/main/src/components/AnalyticalTable/index.tsx +++ b/packages/main/src/components/AnalyticalTable/index.tsx @@ -42,6 +42,7 @@ import { DefaultNoDataComponent } from './defaults/NoDataComponent'; import { useColumnsDependencies } from './hooks/useColumnsDependencies'; import { useDragAndDrop } from './hooks/useDragAndDrop'; import { useDynamicColumnWidths } from './hooks/useDynamicColumnWidths'; +import { useRowHighlight } from "./hooks/useRowHighlight"; import { useRowSelectionColumn } from './hooks/useRowSelectionColumn'; import { useTableCellStyling } from './hooks/useTableCellStyling'; import { useTableHeaderGroupStyling } from './hooks/useTableHeaderGroupStyling'; @@ -95,6 +96,8 @@ export interface TableProps extends CommonProps { rowHeight?: number; alternateRowColor?: boolean; noSelectionColumn?: boolean; + withRowHighlight?: boolean; + highlightField?: string; // features filterable?: boolean; @@ -162,7 +165,9 @@ const AnalyticalTable: FC = forwardRef((props: TableProps, ref: Ref< alternateRowColor, overscanCount, scaleWidthMode, - noSelectionColumn + noSelectionColumn, + withRowHighlight, + highlightField = 'status' } = props; const classes = useStyles({ rowHeight: props.rowHeight }); @@ -210,7 +215,9 @@ const AnalyticalTable: FC = forwardRef((props: TableProps, ref: Ref< alternateRowColor, scaleWidthMode, loading, - noSelectionColumn + noSelectionColumn, + withRowHighlight, + highlightField }, ...reactTableOptions }, @@ -227,6 +234,7 @@ const AnalyticalTable: FC = forwardRef((props: TableProps, ref: Ref< useTableHeaderStyling, useTableRowStyling, useRowSelectionColumn, + useRowHighlight, useDynamicColumnWidths, useColumnsDependencies, useTableCellStyling, From 9ec211dab578c2a6d40d8ee783649fc7403ff4d5 Mon Sep 17 00:00:00 2001 From: MarcusNotheis Date: Thu, 26 Mar 2020 17:49:34 +0100 Subject: [PATCH 2/2] WIP: Add Test --- .../AnalyticalTable/AnalyticalTable.test.tsx | 18 +- .../AnalyticalTable.test.tsx.snap | 609 ++++++++++++++++++ 2 files changed, 626 insertions(+), 1 deletion(-) diff --git a/packages/main/src/components/AnalyticalTable/AnalyticalTable.test.tsx b/packages/main/src/components/AnalyticalTable/AnalyticalTable.test.tsx index f4bc9712adc..115ca758136 100644 --- a/packages/main/src/components/AnalyticalTable/AnalyticalTable.test.tsx +++ b/packages/main/src/components/AnalyticalTable/AnalyticalTable.test.tsx @@ -1,6 +1,7 @@ import { createPassThroughPropsTest } from '@shared/tests/utils'; import { mount } from 'enzyme'; import { AnalyticalTable } from '@ui5/webcomponents-react/lib/AnalyticalTable'; +import { ValueState } from '@ui5/webcomponents-react/lib/ValueState'; import { TableSelectionMode } from '@ui5/webcomponents-react/lib/TableSelectionMode'; import { AnalyticalTableScrollMode } from '@ui5/webcomponents-react/lib/AnalyticalTableScrollMode'; import React, { useRef } from 'react'; @@ -31,7 +32,8 @@ const data = [ friend: { name: 'MAR', age: 28 - } + }, + status: ValueState.Success }, { name: 'bla', @@ -293,5 +295,19 @@ describe('AnalyticalTable', () => { expect(tableInnerRef.scrollTop).toBe(2); }); + test('with highlight row', () => { + const wrapper = mount( + + ); + + expect(wrapper.render()).toMatchSnapshot(); + }); + createPassThroughPropsTest(AnalyticalTable); }); diff --git a/packages/main/src/components/AnalyticalTable/__snapshots__/AnalyticalTable.test.tsx.snap b/packages/main/src/components/AnalyticalTable/__snapshots__/AnalyticalTable.test.tsx.snap index 1599b615ea7..59d35f6b799 100644 --- a/packages/main/src/components/AnalyticalTable/__snapshots__/AnalyticalTable.test.tsx.snap +++ b/packages/main/src/components/AnalyticalTable/__snapshots__/AnalyticalTable.test.tsx.snap @@ -4937,6 +4937,615 @@ exports[`AnalyticalTable test drag and drop of a draggable column 1`] = `
`; +exports[`AnalyticalTable with highlight row 1`] = ` +
+
+ + Table Title + +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ + Name + +
+
+
+ + + + Sort Ascending + + + Sort Descending + + + + +
+
+
+ + Age + +
+
+
+ + + + Sort Ascending + + + Sort Descending + + + + +
+
+
+ + Friend Name + +
+
+
+ + + + Sort Ascending + + + Sort Descending + + + + +
+
+
+ + + Friend Age + + +
+
+
+ + + + Sort Ascending + + + Sort Descending + + + + +
+
+
+
+
+
+
+
+
+
+
+ + Fra + +
+
+ + 40 + +
+
+ + MAR + +
+
+ + 28 + +
+
+
+
+
+
+
+
+
+
+ + bla + +
+
+ + 20 + +
+
+ + Nei + +
+
+ + 50 + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + exports[`AnalyticalTable without selection Column 1`] = `