Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/elements/content-explorer/ContentExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import Content from './Content';
import { isThumbnailAvailable } from '../common/utils';
import { isFocusableElement, isInputElement, focus } from '../../utils/dom';
import { FILE_SHARED_LINK_FIELDS_TO_FETCH } from '../../utils/fields';
import CONTENT_EXPLORER_FOLDER_FIELDS_TO_FETCH from './constants';
import { CONTENT_EXPLORER_FOLDER_FIELDS_TO_FETCH } from './constants';
import LocalStore from '../../utils/LocalStore';
import {
withFeatureConsumer,
Expand Down
73 changes: 54 additions & 19 deletions src/elements/content-explorer/MetadataQueryBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { BoxItemSelection } from '@box/box-item-type-selector';
import isNil from 'lodash/isNil';
import { mapFileTypes } from './utils';

type QueryResult = {
queryParams: { [key: string]: number | Date | string };
Expand Down Expand Up @@ -115,9 +117,7 @@ export const getSelectFilter = (filterValue: string[], fieldKey: string, argInde
return {
queryParams: multiSelectQueryParams,
queries: [
`(${fieldKey === 'mimetype-filter' ? 'item.extension' : fieldKey} HASANY (${Object.keys(
multiSelectQueryParams,
)
`(${fieldKey} HASANY (${Object.keys(multiSelectQueryParams)
.map(argKey => `:${argKey}`)
.join(', ')}))`,
],
Expand All @@ -134,26 +134,61 @@ export const getMimeTypeFilter = (filterValue: string[], fieldKey: string, argIn
};
}

let currentArgIndex = argIndexStart;
// Use mapFileTypes to get the correct extensions and handle special cases
const mappedExtensions = mapFileTypes(filterValue as BoxItemSelection);
if (mappedExtensions.length === 0) {
return {
queryParams: {},
queries: [],
keysGenerated: 0,
};
}

const multiSelectQueryParams = Object.fromEntries(
filterValue.map(value => {
currentArgIndex += 1;
// the item-type-selector is returning the extensions with the suffix 'Type', so we remove it for the query
return [
generateArgKey(fieldKey, currentArgIndex),
String(value.endsWith('Type') ? value.slice(0, -4) : value),
];
}),
);
let currentArgIndex = argIndexStart;
const queryParams: { [key: string]: number | Date | string } = {};
const queries: string[] = [];

// Handle specific extensions and folder type
const extensions: string[] = [];
let hasFolder = false;

for (const extension of mappedExtensions) {
if (extension === 'folder') {
if (!hasFolder) {
currentArgIndex += 1;
const folderArgKey = generateArgKey('mime_folderType', currentArgIndex);
queryParams[folderArgKey] = 'folder';
queries.push(`(item.type = :${folderArgKey})`);
hasFolder = true;
}
} else {
extensions.push(extension);
}
}

return {
queryParams: multiSelectQueryParams,
queries: [
`(item.extension IN (${Object.keys(multiSelectQueryParams)
// Handle extensions in batch if any exist
if (extensions.length > 0) {
const extensionQueryParams = Object.fromEntries(
extensions.map(extension => {
currentArgIndex += 1;
return [generateArgKey(fieldKey, currentArgIndex), extension];
}),
);

Object.assign(queryParams, extensionQueryParams);
queries.push(
`(item.extension IN (${Object.keys(extensionQueryParams)
.map(argKey => `:${argKey}`)
.join(', ')}))`,
],
);
}

// Combine queries with OR if multiple exist
const finalQueries = queries.length > 1 ? [`(${queries.join(' OR ')})`] : queries;

return {
queryParams,
queries: finalQueries,
keysGenerated: currentArgIndex - argIndexStart,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -673,14 +673,20 @@ describe('elements/content-explorer/MetadataQueryAPIHelper', () => {
const filters = {
'mimetype-filter': {
fieldType: 'enum',
value: ['pdf', 'doc'],
value: ['pdfType', 'documentType'],
},
};

const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
expect(result.query).toBe('(item.extension IN (:arg_mimetype_filter_1, :arg_mimetype_filter_2))');
expect(result.query).toBe(
'(item.extension IN (:arg_mimetype_filter_1, :arg_mimetype_filter_2, :arg_mimetype_filter_3, :arg_mimetype_filter_4, :arg_mimetype_filter_5, :arg_mimetype_filter_6))',
);
expect(result.queryParams.arg_mimetype_filter_1).toBe('pdf');
expect(result.queryParams.arg_mimetype_filter_2).toBe('doc');
expect(result.queryParams.arg_mimetype_filter_3).toBe('docx');
expect(result.queryParams.arg_mimetype_filter_4).toBe('gdoc');
expect(result.queryParams.arg_mimetype_filter_5).toBe('rtf');
expect(result.queryParams.arg_mimetype_filter_6).toBe('txt');
});

test('should handle multiple filters of different types', () => {
Expand Down
194 changes: 155 additions & 39 deletions src/elements/content-explorer/__tests__/MetadataQueryBuilder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,19 +228,6 @@ describe('elements/content-explorer/MetadataQueryBuilder', () => {
});
});

test('should handle mimetype-filter field key specially', () => {
const filterValue = ['pdf', 'doc'];
const result = getSelectFilter(filterValue, 'mimetype-filter', 0);
expect(result).toEqual({
queryParams: {
arg_mimetype_filter_1: 'pdf',
arg_mimetype_filter_2: 'doc',
},
queries: ['(item.extension HASANY (:arg_mimetype_filter_1, :arg_mimetype_filter_2))'],
keysGenerated: 2,
});
});

test('should handle single value array', () => {
const filterValue = ['single_value'];
const result = getSelectFilter(filterValue, 'field_name', 0);
Expand Down Expand Up @@ -309,44 +296,51 @@ describe('elements/content-explorer/MetadataQueryBuilder', () => {
});

describe('getMimeTypeFilter', () => {
test('should generate mime type filter and remove "Type" suffix', () => {
const filterValue = ['pdfType', 'docType', 'txtType'];
test('should generate mime type filter using mapFileTypes', () => {
const filterValue = ['pdfType', 'documentType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mimetype_1: 'pdf',
arg_mimetype_2: 'doc',
arg_mimetype_3: 'txt',
arg_mimetype_3: 'docx',
arg_mimetype_4: 'gdoc',
arg_mimetype_5: 'rtf',
arg_mimetype_6: 'txt',
},
queries: ['(item.extension IN (:arg_mimetype_1, :arg_mimetype_2, :arg_mimetype_3))'],
keysGenerated: 3,
queries: [
'(item.extension IN (:arg_mimetype_1, :arg_mimetype_2, :arg_mimetype_3, :arg_mimetype_4, :arg_mimetype_5, :arg_mimetype_6))',
],
keysGenerated: 6,
});
});

test('should handle values without "Type" suffix', () => {
test('should handle values that are not in FILE_FOLDER_TYPES_MAP', () => {
const filterValue = ['pdf', 'doc'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mimetype_1: 'pdf',
arg_mimetype_2: 'doc',
},
queries: ['(item.extension IN (:arg_mimetype_1, :arg_mimetype_2))'],
keysGenerated: 2,
queryParams: {},
queries: [],
keysGenerated: 0,
});
});

test('should handle mixed values with and without "Type" suffix', () => {
const filterValue = ['pdfType', 'doc', 'txtType'];
test('should handle mixed valid and invalid values', () => {
const filterValue = ['pdfType', 'doc', 'documentType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mimetype_1: 'pdf',
arg_mimetype_2: 'doc',
arg_mimetype_3: 'txt',
arg_mimetype_3: 'docx',
arg_mimetype_4: 'gdoc',
arg_mimetype_5: 'rtf',
arg_mimetype_6: 'txt',
},
queries: ['(item.extension IN (:arg_mimetype_1, :arg_mimetype_2, :arg_mimetype_3))'],
keysGenerated: 3,
queries: [
'(item.extension IN (:arg_mimetype_1, :arg_mimetype_2, :arg_mimetype_3, :arg_mimetype_4, :arg_mimetype_5, :arg_mimetype_6))',
],
keysGenerated: 6,
});
});

Expand All @@ -360,16 +354,13 @@ describe('elements/content-explorer/MetadataQueryBuilder', () => {
});
});

test('should handle numeric values converted to strings', () => {
test('should handle numeric values that are not in FILE_FOLDER_TYPES_MAP', () => {
const filterValue = ['123', '456'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mimetype_1: '123',
arg_mimetype_2: '456',
},
queries: ['(item.extension IN (:arg_mimetype_1, :arg_mimetype_2))'],
keysGenerated: 2,
queryParams: {},
queries: [],
keysGenerated: 0,
});
});

Expand Down Expand Up @@ -402,15 +393,140 @@ describe('elements/content-explorer/MetadataQueryBuilder', () => {
});

test('should handle field names with special characters', () => {
const filterValue = ['pdfType', 'docType'];
const filterValue = ['pdfType', 'documentType'];
const result = getMimeTypeFilter(filterValue, 'mime-type.with/special_chars', 0);
expect(result).toEqual({
queryParams: {
arg_mime_type_with_special_chars_1: 'pdf',
arg_mime_type_with_special_chars_2: 'doc',
arg_mime_type_with_special_chars_3: 'docx',
arg_mime_type_with_special_chars_4: 'gdoc',
arg_mime_type_with_special_chars_5: 'rtf',
arg_mime_type_with_special_chars_6: 'txt',
},
queries: [
'(item.extension IN (:arg_mime_type_with_special_chars_1, :arg_mime_type_with_special_chars_2, :arg_mime_type_with_special_chars_3, :arg_mime_type_with_special_chars_4, :arg_mime_type_with_special_chars_5, :arg_mime_type_with_special_chars_6))',
],
keysGenerated: 6,
});
});

// New tests for folderType functionality
test('should handle folderType only', () => {
const filterValue = ['folderType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mime_folderType_1: 'folder',
},
queries: ['(item.type = :arg_mime_folderType_1)'],
keysGenerated: 1,
});
});

test('should handle folderType with file types', () => {
const filterValue = ['folderType', 'pdfType', 'documentType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mime_folderType_1: 'folder',
arg_mimetype_2: 'pdf',
arg_mimetype_3: 'doc',
arg_mimetype_4: 'docx',
arg_mimetype_5: 'gdoc',
arg_mimetype_6: 'rtf',
arg_mimetype_7: 'txt',
},
queries: [
'((item.type = :arg_mime_folderType_1) OR (item.extension IN (:arg_mimetype_2, :arg_mimetype_3, :arg_mimetype_4, :arg_mimetype_5, :arg_mimetype_6, :arg_mimetype_7)))',
],
keysGenerated: 7,
});
});

test('should handle folderType with mixed valid and invalid file types', () => {
const filterValue = ['folderType', 'pdfType', 'doc', 'documentType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mime_folderType_1: 'folder',
arg_mimetype_2: 'pdf',
arg_mimetype_3: 'doc',
arg_mimetype_4: 'docx',
arg_mimetype_5: 'gdoc',
arg_mimetype_6: 'rtf',
arg_mimetype_7: 'txt',
},
queries: [
'((item.type = :arg_mime_folderType_1) OR (item.extension IN (:arg_mimetype_2, :arg_mimetype_3, :arg_mimetype_4, :arg_mimetype_5, :arg_mimetype_6, :arg_mimetype_7)))',
],
keysGenerated: 7,
});
});

test('should handle folderType with single file type', () => {
const filterValue = ['folderType', 'pdfType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mime_folderType_1: 'folder',
arg_mimetype_2: 'pdf',
},
queries: ['((item.type = :arg_mime_folderType_1) OR (item.extension IN (:arg_mimetype_2)))'],
keysGenerated: 2,
});
});

test('should handle folderType with file types using correct arg index', () => {
const filterValue = ['folderType', 'pdfType', 'documentType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 5);
expect(result).toEqual({
queryParams: {
arg_mime_folderType_6: 'folder',
arg_mimetype_7: 'pdf',
arg_mimetype_8: 'doc',
arg_mimetype_9: 'docx',
arg_mimetype_10: 'gdoc',
arg_mimetype_11: 'rtf',
arg_mimetype_12: 'txt',
},
queries: [
'((item.type = :arg_mime_folderType_6) OR (item.extension IN (:arg_mimetype_7, :arg_mimetype_8, :arg_mimetype_9, :arg_mimetype_10, :arg_mimetype_11, :arg_mimetype_12)))',
],
keysGenerated: 7,
});
});

test('should handle multiple folderType entries (should only process one)', () => {
const filterValue = ['folderType', 'pdfType', 'folderType', 'documentType'];
const result = getMimeTypeFilter(filterValue, 'mimetype', 0);
expect(result).toEqual({
queryParams: {
arg_mime_folderType_1: 'folder',
arg_mimetype_2: 'pdf',
arg_mimetype_3: 'doc',
arg_mimetype_4: 'docx',
arg_mimetype_5: 'gdoc',
arg_mimetype_6: 'rtf',
arg_mimetype_7: 'txt',
},
queries: [
'((item.type = :arg_mime_folderType_1) OR (item.extension IN (:arg_mimetype_2, :arg_mimetype_3, :arg_mimetype_4, :arg_mimetype_5, :arg_mimetype_6, :arg_mimetype_7)))',
],
keysGenerated: 7,
});
});

test('should handle folderType with field names containing special characters', () => {
const filterValue = ['folderType', 'pdfType'];
const result = getMimeTypeFilter(filterValue, 'mime-type.with/special_chars', 0);
expect(result).toEqual({
queryParams: {
arg_mime_folderType_1: 'folder',
arg_mime_type_with_special_chars_2: 'pdf',
},
queries: [
'(item.extension IN (:arg_mime_type_with_special_chars_1, :arg_mime_type_with_special_chars_2))',
'((item.type = :arg_mime_folderType_1) OR (item.extension IN (:arg_mime_type_with_special_chars_2)))',
],
keysGenerated: 2,
});
Expand Down
Loading