Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data table Nested columns manager POC #2844

Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import SettingsContainer from '../settings-container';
import messages from './messages';
import { HIDDEN_COLUMNS_PANEL, SELECTED_COLUMNS_PANEL } from './constants';
import { type MessageDescriptor } from 'react-intl';

// 'searchHiddenColums' is only required if 'areHiddenColumnsSearchable' is true
// but that callback is used in AsyncSelectInput.loadOptions which is required
Expand All @@ -42,6 +43,9 @@
};

export type TColumnSettingsManagerProps = {
title?: MessageDescriptor & {
values?: Record<string, React.ReactNode>;
};
availableColumns: TColumnData[];
selectedColumns: TColumnData[];
onUpdateColumns: (updatedColums: TColumnData[]) => void;
Expand Down Expand Up @@ -130,7 +134,7 @@
};

export const ColumnSettingsManager = (props: TColumnSettingsManagerProps) => {
if (props.areHiddenColumnsSearchable) {

Check failure on line 137 in packages/components/data-table-manager/src/column-settings-manager/column-settings-manager.tsx

View workflow job for this annotation

GitHub Actions / build_lint_and_test

rendering with detached data table › should render the layout settings panel when clicking on the dropdown option and interact with the layout options

The above error occurred in the <ColumnSettingsManager> component: at areHiddenColumnsSearchable (packages/components/data-table-manager/src/column-settings-manager/column-settings-manager.tsx:137:13) at div at node_modules/@emotion/react/dist/emotion-element-f93e57b0.cjs.dev.js:62:23 at getStyles$1 (packages/components/spacings/spacings-stack/dist/commercetools-uikit-spacings-stack.cjs.dev.js:76:8) at displaySettings (packages/components/data-table-manager/src/data-table-settings/data-table-settings.tsx:91:11) at div at node_modules/@emotion/react/dist/emotion-element-f93e57b0.cjs.dev.js:62:23 at getStyles$1 (packages/components/spacings/spacings-stack/dist/commercetools-uikit-spacings-stack.cjs.dev.js:76:8) at DataTableManager (packages/components/data-table-manager/src/data-table-manager.tsx:15:61) at TestComponent (packages/components/data-table-manager/src/data-table-manager.spec.js:26:49) at Router (node_modules/react-router/cjs/react-router.js:283:30) at IntlProvider (node_modules/react-intl/src/components/provider.js:33:47) Consider adding an error boundary to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries. at logOrThrow (test/setup-tests.js:62:11) at console.logOrThrow [as error] (test/setup-tests.js:89:3) at logCapturedError (node_modules/react-dom/cjs/react-dom.development.js:20085:23) at update.callback (node_modules/react-dom/cjs/react-dom.development.js:20118:5) at callCallback (node_modules/react-dom/cjs/react-dom.development.js:12318:12) at commitUpdateQueue (node_modules/react-dom/cjs/react-dom.development.js:12339:9) at commitLifeCycles (node_modules/react-dom/cjs/react-dom.development.js:20736:11) at commitLayoutEffects (node_modules/react-dom/cjs/react-dom.development.js:23426:7) at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14) at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25) at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3) at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9) at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17) at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34) at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:3994:16) at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4056:31) at commitRootImpl (node_modules/react-dom/cjs/react-dom.development.js:23151:9) at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:468:12) at runWithPriority$1 (node_modules/react-dom/cjs/react-dom.development.js:11276:10) at commitRoot (node_modules/react-dom/cjs/react-dom.development.js:22990:3) at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:22329:3) at node_modules/react-dom/cjs/react-dom.development.js:11327:26 at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:468:12) at runWithPriority$1 (node_modules/react-dom/cjs/react-dom.development.js:11276:10) at flushSyncCallbackQueueImpl (node_modules/react-dom/cjs/react-dom.development.js:11322:9) at flushSyncCallbackQueue (node_modules/react-dom/cjs/react-dom.development.js:11309:3) at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:22387:7) at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14) at Object.eventWrapper (node_modules/@testing-library/react/dist/pure.js:65:28) at fireEvent (node_modules/@testing-library/dom/dist/events.js:12:35) at Function.fireEvent.<computed> [

Check failure on line 137 in packages/components/data-table-manager/src/column-settings-manager/column-settings-manager.tsx

View workflow job for this annotation

GitHub Actions / build_lint_and_test

rendering with detached data table › should render the layout settings panel when clicking on the dropdown option and interact with the layout options

Error: Uncaught [Error: The above error occurred in the <ColumnSettingsManager> component: at areHiddenColumnsSearchable (packages/components/data-table-manager/src/column-settings-manager/column-settings-manager.tsx:137:13) at div at node_modules/@emotion/react/dist/emotion-element-f93e57b0.cjs.dev.js:62:23 at getStyles$1 (packages/components/spacings/spacings-stack/dist/commercetools-uikit-spacings-stack.cjs.dev.js:76:8) at displaySettings (packages/components/data-table-manager/src/data-table-settings/data-table-settings.tsx:91:11) at div at node_modules/@emotion/react/dist/emotion-element-f93e57b0.cjs.dev.js:62:23 at getStyles$1 (packages/components/spacings/spacings-stack/dist/commercetools-uikit-spacings-stack.cjs.dev.js:76:8) at DataTableManager (packages/components/data-table-manager/src/data-table-manager.tsx:15:61) at TestComponent (packages/components/data-table-manager/src/data-table-manager.spec.js:26:49) at Router (node_modules/react-router/cjs/react-router.js:283:30) at IntlProvider (node_modules/react-intl/src/components/provider.js:33:47) Consider adding an error boundary to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.] at logOrThrow (test/setup-tests.js:62:11) at console.logOrThrow [as error] (test/setup-tests.js:89:3) at reportException (node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:70:28) at Timeout.task [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:525:9)
warning(
typeof props.searchHiddenColumns !== 'undefined',
'ui-kit/ColumnSettingsManager: "searchHiddenColumns" must be provided when "areHiddenColumnsSearchable" is true'
Expand Down Expand Up @@ -178,7 +182,8 @@

return (
<SettingsContainer
title={messages.title}
// @ts-ignore
title={props.title}
closeButtonLabel={messages.closeButtonLabel}
onClose={props.onClose}
primaryButton={props.primaryButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ export const DataTableManagerProvider = ({
topBar,
onSettingsChange,
columnManager,
nestedColumnManager,
}: {
children: React.ReactNode;
columns: TDataTableManagerColumnProps[];
displaySettings: TDataTableSettingsProps['displaySettings'];
topBar: string;
onSettingsChange: () => void;
columnManager: TColumnManagerProps;
nestedColumnManager: TColumnManagerProps[];
}) => {
const decoupledDataTableManagerContext = useMemo(() => {
const areDisplaySettingsEnabled = Boolean(
Expand All @@ -60,9 +62,17 @@ export const DataTableManagerProvider = ({
topBar,
onSettingsChange,
columnManager,
nestedColumnManager,
isCondensed: areDisplaySettingsEnabled && displaySettings!.isCondensed,
};
}, [columns, displaySettings, topBar, onSettingsChange, columnManager]);
}, [
displaySettings,
columns,
topBar,
onSettingsChange,
columnManager,
nestedColumnManager,
]);

return (
<DataTableManagerContext.Provider value={decoupledDataTableManagerContext}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ storiesOf('Components|DataTable', module)
...displaySettingsButtons,
};

// We either provide the columnManager or the nestedColumnManager for backwards compatibility
const columnManager = {
areHiddenColumnsSearchable: boolean('areHiddenColumnsSearchable', true),
searchHiddenColumns: (searchTerm) => {
Expand All @@ -451,14 +452,62 @@ storiesOf('Components|DataTable', module)
...columnManagerButtons,
};

// In a case where we have a nested table, we want to provide multiple table settings
const nestedColumnManager = [
{
label: 'Column manager 1',
value: 'column_manager_1',
areHiddenColumnsSearchable: boolean('areHiddenColumnsSearchable', true),
searchHiddenColumns: (searchTerm) => {
setTableData({
...tableData,
columns: initialColumnsState.filter(
(column) =>
tableData.visibleColumnKeys.includes(column.key) ||
column.label
.toLocaleLowerCase()
.includes(searchTerm.toLocaleLowerCase())
),
});
},
disableColumnManager: boolean('disableColumnManager', false),
visibleColumnKeys: tableData.visibleColumnKeys,
hideableColumns: tableData.columns,
...columnManagerButtons,
},
{
label: 'Column manager 2',
value: 'column_manager_2',
areHiddenColumnsSearchable: boolean('areHiddenColumnsSearchable', true),
searchHiddenColumns: (searchTerm) => {
setTableData({
...tableData,
columns: initialColumnsState.filter(
(column) =>
tableData.visibleColumnKeys.includes(column.key) ||
column.label
.toLocaleLowerCase()
.includes(searchTerm.toLocaleLowerCase())
),
});
},
disableColumnManager: boolean('disableColumnManager', false),
visibleColumnKeys: tableData.visibleColumnKeys,
hideableColumns: tableData.columns,
...columnManagerButtons,
},
];

return (
<DataTableManagerProvider
columns={withRowSelection ? columnsWithSelect : visibleColumns}
displaySettings={displaySettings}
onSettingsChange={(action, nextValue) => {
tableSettingsChangeHandler[action](nextValue);
}}
columnManager={columnManager}
// We either provide the columnManager or the nestedColumnManager for backwards compatibility
// columnManager={columnManager}
nestedColumnManager={nestedColumnManager}
>
<Spacings.Stack>
<header>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { useMemo, cloneElement } from 'react';
import Spacings from '@commercetools-uikit/spacings';
import DataTableSettings from './data-table-settings';
import type { TRow, TColumnProps, TDataTableManagerProps } from './types';
import type {
TRow,
TColumnProps,
TDataTableManagerProps,
TColumnManagerProps,
} from './types';
import { useDataTableManagerContext } from '@commercetools-uikit/data-table-manager/data-table-manager-provider';

const DataTableManager = <Row extends TRow = TRow>(
Expand All @@ -19,6 +24,9 @@ const DataTableManager = <Row extends TRow = TRow>(
const columnManager =
props.columnManager || dataTableManagerContext.columnManager;

const nestedColumnManager =
props.nestedColumnManager || dataTableManagerContext.nestedColumnManager;

const areDisplaySettingsEnabled = Boolean(
displaySettings && !displaySettings.disableDisplaySettings
);
Expand All @@ -45,11 +53,12 @@ const DataTableManager = <Row extends TRow = TRow>(
return (
<Spacings.Stack>
<DataTableSettings
columnManager={columnManager as TColumnManagerProps}
topBar={topBar}
onSettingsChange={onSettingsChange}
columnManager={columnManager}
displaySettings={displaySettings}
managerTheme="light"
nestedColumnManager={nestedColumnManager as TColumnManagerProps[]}
/>
{props.children
? cloneElement(props.children, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ export const getDropdownOptions = ({
areColumnSettingsEnabled,
areDisplaySettingsEnabled,
formatMessage,
nestedColumnManager,
}: {
areColumnSettingsEnabled: boolean;
areDisplaySettingsEnabled: boolean;
formatMessage: (message: MessageDescriptor) => string;
nestedColumnManager: TDataTableSettingsProps['nestedColumnManager'];
}) => [
...(areColumnSettingsEnabled
? [
Expand All @@ -52,6 +54,14 @@ export const getDropdownOptions = ({
},
]
: []),
...(nestedColumnManager
? nestedColumnManager.map((nestedColumns) => {
return {
value: nestedColumns.value,
label: nestedColumns.label,
};
})
: []),
...(areDisplaySettingsEnabled
? [
{
Expand Down Expand Up @@ -94,10 +104,12 @@ const DataTableSettings = (props: TDataTableSettingsProps) => {
const [openedPanelId, setOpenedPanelId] = useState<string | null | undefined>(
null
);
// @ts-ignore
const dropdownOptions: TDropdownOption[] = getDropdownOptions({
areDisplaySettingsEnabled,
areColumnSettingsEnabled,
formatMessage: intl.formatMessage,
nestedColumnManager: props.nestedColumnManager,
});

const mappedColumns = getMappedColumns(
Expand Down Expand Up @@ -166,24 +178,56 @@ const DataTableSettings = (props: TDataTableSettingsProps) => {
managerTheme={props.managerTheme}
/>
)}
{openedPanelId === COLUMN_MANAGER && (
<ColumnSettingsManager
{...(props.columnManager || {})}
availableColumns={props.columnManager?.hideableColumns ?? []}
selectedColumns={selectedColumns}
onClose={handleSettingsPanelChange}
onUpdateColumns={(nextVisibleColumns) => {
const keysOfVisibleColumns = nextVisibleColumns.map(
(visibleColumn) => visibleColumn.key
);
props.onSettingsChange?.(
UPDATE_ACTIONS.COLUMNS_UPDATE,
keysOfVisibleColumns
{props.nestedColumnManager
? props.nestedColumnManager.map((nestedManager) => {
return (
openedPanelId === nestedManager.value && (
<ColumnSettingsManager
key={nestedManager.value}
{...(nestedManager || {})}
availableColumns={nestedManager.hideableColumns ?? []}
title={nestedManager.label}
selectedColumns={
props.nestedColumnManager
? getSelectedColumns(
getMappedColumns(nestedManager.hideableColumns),
nestedManager.visibleColumnKeys
)
: selectedColumns
}
onClose={handleSettingsPanelChange}
onUpdateColumns={(nextVisibleColumns) => {
const keysOfVisibleColumns = nextVisibleColumns.map(
(visibleColumn) => visibleColumn.key
);
props.onSettingsChange?.(
UPDATE_ACTIONS.COLUMNS_UPDATE,
keysOfVisibleColumns
);
}}
managerTheme={props.managerTheme}
/>
)
);
}}
managerTheme={props.managerTheme}
/>
)}
})
: openedPanelId === COLUMN_MANAGER && (
<ColumnSettingsManager
{...(props.columnManager || {})}
availableColumns={props.columnManager?.hideableColumns ?? []}
selectedColumns={selectedColumns}
onClose={handleSettingsPanelChange}
onUpdateColumns={(nextVisibleColumns) => {
const keysOfVisibleColumns = nextVisibleColumns.map(
(visibleColumn) => visibleColumn.key
);
props.onSettingsChange?.(
UPDATE_ACTIONS.COLUMNS_UPDATE,
keysOfVisibleColumns
);
}}
managerTheme={props.managerTheme}
/>
)}
</Spacings.Stack>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ const DensityManager = (props: TDensityManagerProps) => {

return (
<SettingsContainer
title={messages.title}
// Keeping it simple for the purpose of the POC
// @ts-ignore
title="Display settings"
closeButtonLabel={messages.closeButtonLabel}
onClose={props.onClose}
primaryButton={props.primaryButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const SettingsContainer = (props: TSettingsContainerProps) => {
<CardContentWrapper>
<Spacings.Stack scale="xl">
<HeaderContainer>
<Text.Headline as="h2" intlMessage={props.title} />
<Text.Headline as="h2">{props.title}</Text.Headline>
<AccessibleButton
onClick={props.onClose}
label={intl.formatMessage(props.closeButtonLabel)}
Expand Down
7 changes: 7 additions & 0 deletions packages/components/data-table-manager/src/types.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ReactNode, MouseEventHandler, ReactElement } from 'react';
import { MessageDescriptor } from 'react-intl';

export type TColumnData = {
key: string;
Expand Down Expand Up @@ -42,6 +43,10 @@ export type TDisplaySettingsProps = {
};

export type TColumnManagerProps = {
value?: string;
label?: MessageDescriptor & {
values?: Record<string, React.ReactNode>;
};
/**
* Set this to `true` to show a search input for the hidden columns panel.
*/
Expand Down Expand Up @@ -93,6 +98,7 @@ export type TDataTableSettingsProps = {
) => void;
displaySettings?: TDisplaySettingsProps;
columnManager?: TColumnManagerProps;
nestedColumnManager?: TColumnManagerProps[];
managerTheme?: 'light' | 'dark';
};

Expand Down Expand Up @@ -230,4 +236,5 @@ export type TDataTableManagerProps<Row extends TRow = TRow> = {
* Sets the background theme of the Card that contains the settings
*/
managerTheme?: 'light' | 'dark';
nestedColumnManager?: TDataTableSettingsProps['nestedColumnManager'];
};
Loading