Skip to content

Commit

Permalink
[BulkActions] Ensure we rollup flat actions arrays as a single sect…
Browse files Browse the repository at this point in the history
…ion within the ActionList (#11663)

### WHY are these changes introduced?

Fixes Shopify/web#119797

The BulkActions component in Polaris takes two different shapes of
objects as possible items within the `actions` array. They can either be
regular actions, shaped like

```js
{
  content: 'Action label', 
  onAction: () => console.log('Performed action') 
}
``` 

or groups of actions, shaped like 
```js
{ 
  title: 'Action group', 
  items: [ 
    { 
      content: 'Action label 1', 
      onAction: () => console.log('Performed action 1') 
    }, 
    { 
      content: 'Action label 2', 
      onAction: () => console.log('Performed action 2') 
    }
  ] 
}
```

Previous to our recent update to the BulkActions, we had some logic that
would look for the presence of these two types of objects within the
`actions` prop. If it detected all items were of the first type, it
would roll them up into a single section in the `ActionList`. If it
detected all items were of the second type, it would put each action
group into its own section within the `ActionList`. However, if you
passed an `actions` prop which comprised of a combination of both
shapes, we returned absolutely nothing 😬

Our recent update fixed this bug, so we now support a combination of
action shapes in the `actions` prop, however we need to re-introduce the
logic to roll each action into a single section in the `ActionList` if
we detect that every action is the first type mentioned above, as we
currently render each action in its own section, which is unnecessary.

### How to 🎩

🖥 [Local development
instructions](https://github.com/Shopify/polaris/blob/main/README.md#install-dependencies-and-build-workspaces)
🗒 [General tophatting
guidelines](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md)
📄 [Changelog
guidelines](https://github.com/Shopify/polaris/blob/main/.github/CONTRIBUTING.md#changelog)

Spin URL for change:
https://admin.web.bulk-actions-rollup.marc-thomas.eu.spin.dev/store/shop1/products/7

### 🎩 checklist

- [x] Tested a
[snapshot](https://github.com/Shopify/polaris/blob/main/documentation/Releasing.md#-snapshot-releases)
- [x] Tested on
[mobile](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md#cross-browser-testing)
- [x] Tested on [multiple
browsers](https://help.shopify.com/en/manual/shopify-admin/supported-browsers)
- [x] Tested for
[accessibility](https://github.com/Shopify/polaris/blob/main/documentation/Accessibility%20testing.md)
- [x] Updated the component's `README.md` with documentation changes
- [x] [Tophatted
documentation](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting%20documentation.md)
changes in the style guide
  • Loading branch information
mrcthms committed Feb 28, 2024
1 parent 60d9f83 commit ab28772
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-glasses-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris': minor
---

Updated `BulkActions` to support containing a flat array of actions into a single section within the ActionList
43 changes: 26 additions & 17 deletions polaris-react/src/components/BulkActions/BulkActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
useState,
useEffect,
useCallback,
useMemo,
} from 'react';

import {classNames} from '../../utilities/css';
Expand Down Expand Up @@ -283,22 +284,26 @@ export const BulkActions = forwardRef(function BulkActions(
items: mergedHiddenPromotedActions,
};

const allHiddenActions = actions
? actions
.filter((action) => action)
.map(
(
action: BulkAction | MenuGroupDescriptor | BulkActionListSection,
) => {
if (instanceOfBulkActionListSection(action)) {
return {items: [...action.items]};
} else if (instanceOfMenuGroupDescriptor(action)) {
return {items: [...action.actions]};
}
return {items: [action]};
},
)
: [];
const allHiddenActions = useMemo(() => {
if (actionSections) {
return actionSections;
}
if (!actions) {
return [];
}
return actions
.filter((action) => action)
.map(
(action: BulkAction | MenuGroupDescriptor | BulkActionListSection) => {
if (instanceOfBulkActionListSection(action)) {
return {items: [...action.items]};
} else if (instanceOfMenuGroupDescriptor(action)) {
return {items: [...action.actions]};
}
return {items: [action]};
},
);
}, [actions, actionSections]);

const activator = (
<BulkActionButton
Expand All @@ -321,7 +326,11 @@ export const BulkActions = forwardRef(function BulkActions(
onClose={togglePopover}
>
<ActionList
sections={[hiddenPromotedSection, ...allHiddenActions]}
sections={
hiddenPromotedSection.items.length > 0
? [hiddenPromotedSection, ...allHiddenActions]
: allHiddenActions
}
onActionAnyItem={togglePopover}
/>
</Popover>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,34 @@ describe('<BulkActions />', () => {

expect(bulkActionsCount).toBe(0);
});

it('renders a flat map of actions in a section', () => {
const bulkActions = mountWithApp(
<BulkActions
{...bulkActionProps}
promotedActions={[]}
actions={[
{content: 'Action 1'},
{content: 'Action 2'},
{content: 'Action 3'},
]}
/>,
);

bulkActions.find(BulkActionButton)?.trigger('onAction');

expect(bulkActions).toContainReactComponent(ActionList, {
sections: [
{
items: [
{content: 'Action 1'},
{content: 'Action 2'},
{content: 'Action 3'},
],
},
],
});
});
});

describe('loading', () => {
Expand Down
16 changes: 16 additions & 0 deletions polaris-react/src/components/IndexTable/IndexTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,22 @@ export function WithBulkActionsAndSelectionAcrossPages() {
content: 'Delete customers',
onAction: () => console.log('Todo: implement bulk delete'),
},
{
content: 'Edit prices',
onAction: () => console.log('Todo: implement bulk delete'),
},
{
content: 'Edit quantities',
onAction: () => console.log('Todo: implement bulk delete'),
},
{
content: 'Edit SKUs',
onAction: () => console.log('Todo: implement bulk delete'),
},
{
content: 'Edit barcodes',
onAction: () => console.log('Todo: implement bulk delete'),
},
];

const rowMarkup = customers.map(
Expand Down

0 comments on commit ab28772

Please sign in to comment.