Skip to content

Commit fac795f

Browse files
fix(metadata-view): Enable sorting dropdown (#4265)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent baaaa83 commit fac795f

File tree

4 files changed

+114
-41
lines changed

4 files changed

+114
-41
lines changed

src/elements/content-explorer/ContentExplorer.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export interface ContentExplorerProps {
145145
metadataQuery?: MetadataQuery;
146146
metadataViewProps?: Omit<
147147
MetadataViewContainerProps,
148-
'hasError' | 'currentCollection' | 'metadataTemplate' | 'onMetadataFilter'
148+
'hasError' | 'currentCollection' | 'metadataTemplate' | 'selectedKeys'
149149
>;
150150
onCreate?: (item: BoxItem) => void;
151151
onDelete?: (item: BoxItem) => void;
@@ -1647,7 +1647,10 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
16471647
return maxWidthColumns;
16481648
};
16491649

1650-
getMetadataViewProps = (): ContentExplorerProps['metadataViewProps'] => {
1650+
getMetadataViewProps = (): Omit<
1651+
MetadataViewContainerProps,
1652+
'hasError' | 'currentCollection' | 'metadataTemplate'
1653+
> => {
16511654
const { metadataViewProps } = this.props;
16521655
const { onSelectionChange } = metadataViewProps ?? {};
16531656
const { selectedItemIds } = this.state;

src/elements/content-explorer/MetadataViewContainer.tsx

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ const MetadataViewContainer = ({
155155
const clonedTemplate = cloneDeep(metadataTemplate);
156156
let fields = clonedTemplate?.fields || [];
157157

158+
// Filter fields to only include those that have corresponding columns
159+
const columnIds = newColumns.map(col => col.id);
160+
fields = fields.filter((field: MetadataTemplateField) => {
161+
// For metadata fields, check if the column ID matches the field key
162+
// Column IDs for metadata fields are typically in format: metadata.template.fieldKey
163+
return columnIds.some(columnId => {
164+
const trimmedColumnId = trimMetadataFieldPrefix(columnId);
165+
return trimmedColumnId === field.key;
166+
});
167+
});
168+
158169
// Check if item_name field already exists to avoid duplicates
159170
const hasItemNameField = fields.some((field: MetadataTemplateField) => field.key === ITEM_FILTER_NAME);
160171

@@ -185,7 +196,7 @@ const MetadataViewContainer = ({
185196
}) || [],
186197
},
187198
];
188-
}, [formatMessage, metadataTemplate]);
199+
}, [formatMessage, metadataTemplate, newColumns]);
189200

190201
const initialFilterValues = React.useMemo(
191202
() => transformInitialFilterValuesToInternal(initialFilterValuesProp),
@@ -203,20 +214,6 @@ const MetadataViewContainer = ({
203214
[onFilterSubmit, onMetadataFilter],
204215
);
205216

206-
const transformedActionBarProps = React.useMemo(() => {
207-
return {
208-
...actionBarProps,
209-
initialFilterValues,
210-
onFilterSubmit: handleFilterSubmit,
211-
filterGroups,
212-
213-
predefinedFilterOptions: {
214-
[PredefinedFilterName.KeywordSearchFilterGroup]: { isDisabled: true },
215-
[PredefinedFilterName.LocationFilterGroup]: { isDisabled: true },
216-
},
217-
};
218-
}, [actionBarProps, initialFilterValues, handleFilterSubmit, filterGroups]);
219-
220217
// Create a wrapper function that calls both. The wrapper function should follow the signature of onSortChange from RAC
221218
const handleSortChange = React.useCallback(
222219
({ column, direction }: SortDescriptor) => {
@@ -239,6 +236,22 @@ const MetadataViewContainer = ({
239236
[onSortChangeInternal, tableProps],
240237
);
241238

239+
const transformedActionBarProps = React.useMemo(() => {
240+
return {
241+
...actionBarProps,
242+
initialFilterValues,
243+
onFilterSubmit: handleFilterSubmit,
244+
filterGroups,
245+
sortDropdownProps: {
246+
onSortChange: handleSortChange,
247+
},
248+
predefinedFilterOptions: {
249+
[PredefinedFilterName.KeywordSearchFilterGroup]: { isDisabled: true },
250+
[PredefinedFilterName.LocationFilterGroup]: { isDisabled: true },
251+
},
252+
};
253+
}, [actionBarProps, initialFilterValues, handleFilterSubmit, handleSortChange, filterGroups]);
254+
242255
// Create new tableProps with our wrapper function
243256
const newTableProps = {
244257
...tableProps,

src/elements/content-explorer/__tests__/ContentExplorer.test.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -442,12 +442,7 @@ describe('elements/content-explorer/ContentExplorer', () => {
442442
'name',
443443
],
444444
};
445-
const fieldsToShow = [
446-
{ key: `${metadataFieldNamePrefix}.name`, canEdit: false, displayName: 'Alias' },
447-
{ key: `${metadataFieldNamePrefix}.industry`, canEdit: true },
448-
{ key: `${metadataFieldNamePrefix}.last_contacted_at`, canEdit: true },
449-
{ key: `${metadataFieldNamePrefix}.role`, canEdit: true },
450-
];
445+
451446
const columns = [
452447
{
453448
// Always include the name column
@@ -472,9 +467,9 @@ describe('elements/content-explorer/ContentExplorer', () => {
472467
metadataViewProps: {
473468
columns,
474469
isSelectionEnabled: true,
470+
onMetadataFilter: jest.fn(),
475471
},
476472
metadataQuery,
477-
fieldsToShow,
478473
defaultView,
479474
features: {
480475
contentExplorer: {

src/elements/content-explorer/__tests__/MetadataViewContainer.test.tsx

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ describe('elements/content-explorer/MetadataViewContainer', () => {
3333
];
3434

3535
const mockMetadataTemplateFields: MetadataTemplateField[] = [
36-
{
37-
id: 'field1',
38-
key: 'item.name',
39-
displayName: 'Name',
40-
type: 'string',
41-
},
4236
{
4337
id: 'field2',
4438
key: 'industry',
@@ -101,6 +95,30 @@ describe('elements/content-explorer/MetadataViewContainer', () => {
10195
minWidth: 250,
10296
maxWidth: 250,
10397
},
98+
{
99+
textValue: 'Contact Role',
100+
id: 'role',
101+
type: 'string',
102+
allowsSorting: true,
103+
minWidth: 250,
104+
maxWidth: 250,
105+
},
106+
{
107+
textValue: 'Status',
108+
id: 'status',
109+
type: 'string',
110+
allowsSorting: true,
111+
minWidth: 250,
112+
maxWidth: 250,
113+
},
114+
{
115+
textValue: 'Price',
116+
id: 'price',
117+
type: 'string',
118+
allowsSorting: true,
119+
minWidth: 250,
120+
maxWidth: 250,
121+
},
104122
],
105123
metadataTemplate: mockMetadataTemplate,
106124
onMetadataFilter: jest.fn(),
@@ -264,9 +282,10 @@ describe('elements/content-explorer/MetadataViewContainer', () => {
264282
actionBarProps: { initialFilterValues },
265283
});
266284

267-
expect(screen.getByRole('button', { name: 'All Filters 3' })).toBeInTheDocument();
285+
expect(screen.getByRole('button', { name: 'All Filters 2' })).toBeInTheDocument();
268286
expect(screen.getByRole('button', { name: /Industry/i })).toHaveTextContent(/\(1\)/);
269-
expect(screen.getByRole('button', { name: /Category/i })).toHaveTextContent(/\(2\)/);
287+
// Category filter should not be present since there's no corresponding column
288+
expect(screen.queryByRole('button', { name: /Category/i })).not.toBeInTheDocument();
270289
});
271290

272291
test('should handle empty metadata template fields', () => {
@@ -334,12 +353,6 @@ describe('elements/content-explorer/MetadataViewContainer', () => {
334353
const templateWithoutOptions: MetadataTemplate = {
335354
...mockMetadataTemplate,
336355
fields: [
337-
{
338-
id: 'field1',
339-
key: 'name',
340-
displayName: 'File Name',
341-
type: 'string',
342-
},
343356
{
344357
id: 'field2',
345358
key: 'industry',
@@ -350,11 +363,11 @@ describe('elements/content-explorer/MetadataViewContainer', () => {
350363
],
351364
};
352365

353-
renderComponent({ metadataTemplate: templateWithoutOptions });
366+
renderComponent({
367+
metadataTemplate: templateWithoutOptions,
368+
});
354369

355370
expect(screen.getByRole('button', { name: 'All Filters' })).toBeInTheDocument();
356-
expect(screen.getAllByRole('button', { name: 'Name' })).toHaveLength(1); // Only the one added by component
357-
expect(screen.getByRole('button', { name: 'File Name' })).toBeInTheDocument();
358371
expect(screen.getByRole('button', { name: 'Industry' })).toBeInTheDocument();
359372
});
360373

@@ -546,4 +559,53 @@ describe('elements/content-explorer/MetadataViewContainer', () => {
546559
).not.toBeInTheDocument();
547560
});
548561
});
562+
563+
test('should filter fields based on columns provided', () => {
564+
const template: MetadataTemplate = {
565+
...mockMetadataTemplate,
566+
fields: [
567+
{
568+
id: 'field1',
569+
key: 'status',
570+
displayName: 'Status',
571+
type: 'enum',
572+
options: [
573+
{ id: 's1', key: 'Active' },
574+
{ id: 's2', key: 'Inactive' },
575+
],
576+
},
577+
{
578+
id: 'field2',
579+
key: 'price',
580+
displayName: 'Price',
581+
type: 'float',
582+
},
583+
{
584+
id: 'field3',
585+
key: 'category',
586+
displayName: 'Category',
587+
type: 'multiSelect',
588+
options: [
589+
{ id: 'c1', key: 'tech' },
590+
{ id: 'c2', key: 'finance' },
591+
],
592+
},
593+
],
594+
};
595+
596+
// Only provide columns for 'status' and 'price', not 'category'
597+
renderComponent({
598+
metadataTemplate: template,
599+
});
600+
601+
// Should show filters for fields that have corresponding columns
602+
expect(screen.getByRole('button', { name: 'All Filters' })).toBeInTheDocument();
603+
expect(screen.getByRole('button', { name: 'Status' })).toBeInTheDocument();
604+
expect(screen.getByRole('button', { name: 'Price' })).toBeInTheDocument();
605+
606+
// Should NOT show filter for 'category' since there's no corresponding column
607+
expect(screen.queryByRole('button', { name: 'Category' })).not.toBeInTheDocument();
608+
// Should NOT show filter for 'industry' since it's not in the provided columns
609+
expect(screen.queryByRole('button', { name: 'Industry' })).not.toBeInTheDocument();
610+
});
549611
});

0 commit comments

Comments
 (0)