Skip to content

Commit 9d44fa7

Browse files
JuliRossiFBanfi
andauthored
Bulk edit v1.2[] (#10093)
* Bulk-Edit-App: Fix sorting error and edit button with no padding [INTEG-3103] (#10090) * Bulk-Edit-App: Freeze top row with Field Names [INTEG-2953] (#10076) * freeze top row with Field Names * removing unused import * making the status column sticky too (#10082) * not showing the edit button when loading entries * fix error when changing sorting * Bulk edit: Filter columns [INTEG-3089] (#10089) * Bulk-Edit-App: Freeze top row with Field Names [INTEG-2953] (#10076) * freeze top row with Field Names * removing unused import * making the status column sticky too (#10082) * wip * select all * Refactor FilterColumns and SortMenu components for improved layout and functionality * Fixing states and enhancing performance in the process by not calling the getContentType each time * Fix box issue * Renaming and fixing warnings * sticky * corrections PR comments * Fixing rebase conflicts --------- Co-authored-by: Franco Banfi <62450599+FBanfi@users.noreply.github.com> Co-authored-by: francobanfi <franco.banfi@external.contentful.com> * fixing view numbers (#10092) --------- Co-authored-by: Franco Banfi <62450599+FBanfi@users.noreply.github.com> Co-authored-by: francobanfi <franco.banfi@external.contentful.com>
1 parent df43ff6 commit 9d44fa7

11 files changed

Lines changed: 521 additions & 131 deletions

File tree

apps/bulk-edit/package-lock.json

Lines changed: 73 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/bulk-edit/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"dependencies": {
66
"@contentful/app-sdk": "^4.29.1",
77
"@contentful/f36-components": "4.79.1",
8+
"@contentful/f36-multiselect": "^4.81.1",
89
"@contentful/f36-navlist": "^4.1.0-alpha.1",
910
"@contentful/f36-tokens": "4.2.0",
1011
"@contentful/field-editor-json": "^3.3.38",
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Flex } from '@contentful/f36-components';
2+
import { Multiselect, MultiselectOption } from '@contentful/f36-multiselect';
3+
import { css } from 'emotion';
4+
import { CSSProperties, useMemo } from 'react';
5+
import { truncate } from '../utils/entryUtils';
6+
import { ColumnOption } from '../types';
7+
import tokens from '@contentful/f36-tokens';
8+
9+
const ColumnMultiselect = ({
10+
options,
11+
selectedFields,
12+
setSelectedFields,
13+
style,
14+
}: {
15+
options: ColumnOption[];
16+
selectedFields: ColumnOption[];
17+
setSelectedFields: (fields: ColumnOption[]) => void;
18+
style?: CSSProperties;
19+
}) => {
20+
const getPlaceholderText = () => {
21+
if (selectedFields.length === 0) return 'No fields selected';
22+
if (selectedFields.length === options.length) return 'Filter fields';
23+
if (selectedFields.length === 1) return selectedFields[0].label;
24+
return `${selectedFields[0].label} and ${selectedFields.length - 1} more`;
25+
};
26+
27+
const toggleAll = (e: React.ChangeEvent<HTMLInputElement>) => {
28+
const checked = e.target.checked;
29+
if (checked) {
30+
setSelectedFields(options);
31+
} else {
32+
setSelectedFields([]);
33+
}
34+
};
35+
36+
const areAllSelected = useMemo(() => {
37+
return options.every((option) => selectedFields.some((field) => field.value === option.value));
38+
}, [selectedFields, options]);
39+
40+
return (
41+
<Flex gap="spacing2Xs" flexDirection="column" style={style}>
42+
<Multiselect
43+
placeholder={getPlaceholderText()}
44+
triggerButtonProps={{ size: 'small' }}
45+
popoverProps={{ isFullWidth: true }}>
46+
<Multiselect.SelectAll onSelectItem={toggleAll} isChecked={areAllSelected} />
47+
{options.map((option) => (
48+
<MultiselectOption
49+
className={css`
50+
font-size: ${tokens.fontSizeS};
51+
`}
52+
key={option.value}
53+
label={truncate(option.label, 30)}
54+
value={option.value}
55+
itemId={option.value}
56+
isChecked={selectedFields.some((field) => field.value === option.value)}
57+
onSelectItem={(e) => {
58+
const checked = e.target.checked;
59+
if (checked) {
60+
setSelectedFields([...selectedFields, option]);
61+
} else {
62+
setSelectedFields(selectedFields.filter((field) => field.value !== option.value));
63+
}
64+
}}
65+
/>
66+
))}
67+
</Multiselect>
68+
</Flex>
69+
);
70+
};
71+
72+
export default ColumnMultiselect;

apps/bulk-edit/src/locations/Page/components/SortMenu.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useMemo, useState } from 'react';
1+
import React, { useState } from 'react';
22
import { Box, Menu, Button } from '@contentful/f36-components';
33

44
import { styles } from '../styles';
@@ -19,25 +19,20 @@ interface SortMenuProps {
1919
export const SortMenu: React.FC<SortMenuProps> = ({ sortOption, onSortChange }) => {
2020
const [isOpen, setIsOpen] = useState(false);
2121

22-
const sortOptionLabel = useMemo(() => {
23-
const label = SORT_OPTIONS.find((option) => option.value === sortOption)?.label!;
24-
return label.charAt(0).toLowerCase() + label.slice(1);
25-
}, [sortOption]);
26-
2722
return (
2823
<Box marginBottom="spacingM" marginTop="spacingM" style={styles.sortMenu}>
29-
<Menu isFullWidth onOpen={() => setIsOpen(true)} onClose={() => setIsOpen(false)}>
24+
<Menu onOpen={() => setIsOpen(true)} onClose={() => setIsOpen(false)}>
3025
<Menu.Trigger>
3126
<Button
3227
variant="secondary"
3328
size="small"
3429
startIcon={<SortDescendingIcon size={16} />}
3530
endIcon={isOpen ? <CaretUpIcon size={16} /> : <CaretDownIcon size={16} />}
36-
aria-label="Sort display name by">
37-
Sort by {sortOptionLabel}
31+
aria-label="Sort by">
32+
Sort by
3833
</Button>
3934
</Menu.Trigger>
40-
<Menu.List>
35+
<Menu.List style={styles.sortMenuList}>
4136
{SORT_OPTIONS.map((option) => (
4237
<Menu.Item
4338
key={option.value}

apps/bulk-edit/src/locations/Page/components/TableHeader.tsx

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,17 @@ export const TableHeader: React.FC<TableHeaderProps> = ({
2323
return (
2424
<Table.Head style={styles.tableHead}>
2525
<Table.Row style={styles.stickyTableRow}>
26-
<Box style={styles.stickyMainColumnsOrFields}>
27-
{fields.length > 0 && (
28-
<Table.Cell as="th" key={DISPLAY_NAME_COLUMN} style={styles.tableHeader}>
29-
Display name
30-
</Table.Cell>
31-
)}
32-
<Table.Cell as="th" key={ENTRY_STATUS_COLUMN} style={styles.tableHeader}>
33-
<Flex gap="spacingXs" alignItems="center" justifyContent="flex-start">
34-
Status
35-
<Tooltip content="Bulk editing is not supported for Status" placement="top">
36-
<QuestionIcon size={16} aria-label="Bulk editing not supported for Status" />
37-
</Tooltip>
38-
</Flex>
39-
</Table.Cell>
40-
</Box>
26+
<Table.Cell as="th" key={DISPLAY_NAME_COLUMN} style={styles.displayNameHeader}>
27+
Display name
28+
</Table.Cell>
29+
<Table.Cell as="th" key={ENTRY_STATUS_COLUMN} style={styles.statusHeader}>
30+
<Flex gap="spacingXs" alignItems="center" justifyContent="flex-start">
31+
Status
32+
<Tooltip content="Bulk editing is not supported for Status" placement="top">
33+
<QuestionIcon size={16} aria-label="Bulk editing not supported for Status" />
34+
</Tooltip>
35+
</Flex>
36+
</Table.Cell>
4137
{fields.map((field) => {
4238
const isAllowed = isCheckboxAllowed(field);
4339
const isDisabled = checkboxesDisabled[field.uniqueId];

0 commit comments

Comments
 (0)