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

chore: Updates property filter demos to feature token groups #160

Merged
merged 2 commits into from
Sep 18, 2024
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
28 changes: 19 additions & 9 deletions src/fake-server/distributions.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,26 @@ function filterItemsByProperty(options) {
};

const filteringFunction = function (item, tokens, operation) {
function filterWithToken(include, opFn, tokenOrGroup) {
if ('operation' in tokenOrGroup) {
const nextOpFn = operationFn(tokenOrGroup.operation);
return tokenOrGroup.tokens.reduce(
(include, token) => filterWithToken(include, nextOpFn, token),
operation === 'and'
);
}
if ('operator' in tokenOrGroup) {
const comparator = getComparatorForOperator(tokenOrGroup.operator);
const searchableProps = tokenOrGroup.propertyKey ? [tokenOrGroup.propertyKey] : Object.keys(item);
return searchableProps.some(propertyKey => {
const matched = match(propertyKey, tokenOrGroup.value, item, comparator);
return opFn(include, matched);
});
}
throw new Error('Invariant violation: unexpected token shape.');
}
const opFn = operationFn(operation);
return tokens.reduce((include, token) => {
const comparator = getComparatorForOperator(token.operator);
const searchableProps = token.propertyKey ? [token.propertyKey] : Object.keys(item);

return searchableProps.some(propertyKey => {
const matched = match(propertyKey, token.value, item, comparator);
return opFn(include, matched);
});
}, operation === 'and');
return tokens.reduce((include, token) => filterWithToken(include, opFn, token), operation === 'and');
};

return items.filter(item => filteringFunction(item, options.filteringTokens, options.filteringOperation));
Expand Down
3 changes: 2 additions & 1 deletion src/pages/server-side-table-property-filter/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function ServerSidePropertyFilterTable({ columnDefinitions, saveWidths, loadHelp
sortingDescending,
},
filtering: {
filteringTokens: filteringQuery.tokens,
filteringTokens: filteringQuery.tokenGroups ?? filteringQuery.tokens,
filteringOperation: filteringQuery.operation,
},
};
Expand Down Expand Up @@ -119,6 +119,7 @@ function ServerSidePropertyFilterTable({ columnDefinitions, saveWidths, loadHelp
customGroupsText={[{ group: 'tags', properties: 'Tags', values: 'Tags values' }]}
countText={getTextFilterCounterServerSideText(items, pagesCount, pageSize)}
expandToViewport={true}
enableTokenGroups={true}
/>
}
pagination={
Expand Down
13 changes: 6 additions & 7 deletions src/pages/table-date-filter/table-date-filter-forms.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import Calendar from '@cloudscape-design/components/calendar';
import DateInput from '@cloudscape-design/components/date-input';
import FormField from '@cloudscape-design/components/form-field';
import TimeInput from '@cloudscape-design/components/time-input';
import SpaceBetween from '@cloudscape-design/components/space-between';
import DatePicker from '@cloudscape-design/components/date-picker';

export function DateTimeForm({ filter, operator, value, onChange }) {
Expand Down Expand Up @@ -61,11 +60,11 @@ export function DateTimeForm({ filter, operator, value, onChange }) {
if (typeof filter !== 'undefined') {
return (
<div className="date-time-form">
<FormField description="Date" constraintText="Use YYYY/MM/DD format.">
<FormField description="Date">
<DateInput {...dateInputProps} />
</FormField>

<FormField description="Time" constraintText="Use 24-hour format.">
<FormField description="Time">
<TimeInput {...timeInputProps} />
</FormField>

Expand All @@ -75,15 +74,15 @@ export function DateTimeForm({ filter, operator, value, onChange }) {
}

return (
<SpaceBetween direction="vertical" size="m">
<FormField description="Date" constraintText="Use YYYY/MM/DD format.">
<div className="date-time-form">
<FormField description="Date">
<DatePicker {...dateInputProps} {...calendarProps} />
</FormField>

<FormField description="Time" constraintText="Use 24-hour format.">
<FormField description="Time">
<TimeInput {...timeInputProps} />
</FormField>
</SpaceBetween>
</div>
);
}

Expand Down
1 change: 1 addition & 0 deletions src/pages/table-expandable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ function App() {
filteringOptions={filteringOptions}
countText={getTextFilterCounterText(filteredItemsCount ?? 0)}
filteringPlaceholder="Search databases"
enableTokenGroups={true}
/>
}
expandableRows={expandableRows}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export function PropertyFilterTable({
i18nStrings={propertyFilterI18nStrings}
countText={getTextFilterCounterText(filteredItemsCount)}
expandToViewport={true}
enableTokenGroups={true}
/>
}
pagination={<Pagination {...paginationProps} />}
Expand Down
53 changes: 30 additions & 23 deletions src/pages/table-saved-filters/filter-set-modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,39 @@ function queryToString(
query: PropertyFilterProps.Query,
filteringProperties?: readonly PropertyFilterProps.FilteringProperty[]
): string {
return query.tokens
.map(({ operator, value, propertyKey }) => {
if (propertyKey) {
const property = filteringProperties?.find(({ key }) => key === propertyKey);
const keyLabel = property?.propertyLabel ?? propertyKey;
function tokenToString({ operator, value, propertyKey }: PropertyFilterProps.Token): string {
if (propertyKey) {
const property = filteringProperties?.find(({ key }) => key === propertyKey);
const keyLabel = property?.propertyLabel ?? propertyKey;

let valueLabel = value;
let valueLabel = value;

// See if there is a custom value formatter defined for this property and operator
if (property && property.operators) {
property.operators.forEach(propertyOperator => {
if (
typeof propertyOperator !== 'string' &&
propertyOperator.operator === operator &&
propertyOperator.format
) {
valueLabel = propertyOperator.format(value);
}
});
}

return `${keyLabel} ${operator} ${valueLabel}`;
// See if there is a custom value formatter defined for this property and operator
if (property && property.operators) {
property.operators.forEach(propertyOperator => {
if (
typeof propertyOperator !== 'string' &&
propertyOperator.operator === operator &&
propertyOperator.format
) {
valueLabel = propertyOperator.format(value);
}
});
}
return value;
})
.join(`, ${query.operation} `);
return `${keyLabel} ${operator} ${valueLabel}`;
}
return operator === ':' ? value : `${operator} ${value}`;
}

function tokenOrGroupToString(tokenOrGroup: PropertyFilterProps.TokenGroup | PropertyFilterProps.Token): string {
if ('operation' in tokenOrGroup) {
return '(' + tokenOrGroup.tokens.map(tokenOrGroupToString).join(`, ${tokenOrGroup.operation} `) + ')';
} else {
return tokenToString(tokenOrGroup);
}
}

return (query.tokenGroups || query.tokens).map(tokenOrGroupToString).join(`, ${query.operation} `);
orangevolon marked this conversation as resolved.
Show resolved Hide resolved
}

export function SaveFilterSetModal({
Expand Down
28 changes: 19 additions & 9 deletions src/pages/table-saved-filters/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,7 @@
import React, { useRef, useState, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
import { useCollection } from '@cloudscape-design/collection-hooks';
import {
ButtonDropdown,
FormField,
Flashbar,
Pagination,
PropertyFilter,
Select,
Table,
} from '@cloudscape-design/components';
import { ButtonDropdown, Flashbar, Pagination, PropertyFilter, Select, Table } from '@cloudscape-design/components';
import { FILTERING_PROPERTIES } from '../table-property-filter/table-property-filter-config';
import { COLUMN_DEFINITIONS, DEFAULT_PREFERENCES } from '../commons/table-config';
import { useDisclaimerFlashbarItem } from '../commons/disclaimer-flashbar-item';
Expand Down Expand Up @@ -50,6 +42,23 @@ const defaultFilterSets = [
tokens: [{ propertyKey: 'origin', operator: ':', value: 'BUCKET' }],
},
},
{
name: 'Best performance in buckets 1,2',
query: {
operation: 'and',
tokenGroups: [
{
operation: 'or',
tokens: [
{ propertyKey: 'origin', operator: '=', value: 'EXAMPLE-BUCKET-1.s3.amazon' },
{ propertyKey: 'origin', operator: '=', value: 'EXAMPLE-BUCKET-2.s3.amazon' },
],
},
{ propertyKey: 'priceClass', operator: '=', value: 'Use all edge locations (best performance)' },
],
tokens: [],
},
},
];

function App() {
Expand Down Expand Up @@ -170,6 +179,7 @@ function App() {
i18nStrings={propertyFilterI18nStrings}
countText={getTextFilterCounterText(filteredItemsCount)}
expandToViewport={true}
enableTokenGroups={true}
customControl={
<Select
{...selectProps}
Expand Down
21 changes: 8 additions & 13 deletions src/pages/table-saved-filters/use-filter-sets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ButtonDropdownProps } from '@cloudscape-design/components/button-dropdo
import { SelectProps } from '@cloudscape-design/components/select';
import { DeleteFilterSetModal, SaveFilterSetModal, UpdateFilterSetModal } from './filter-set-modals';
import { FlashbarProps } from '@cloudscape-design/components/flashbar';
import { isEqual } from 'lodash';

export interface FilterSet {
name: string;
Expand Down Expand Up @@ -34,18 +35,12 @@ export interface UseFilterSetsResult {

type FilterAction = 'update' | 'new' | 'delete';

function isQueryEmpty(query: PropertyFilterProps.Query) {
return (!query.tokenGroups || query.tokenGroups.length === 0) && query.tokens.length === 0;
}

function isQueryEqual(queryA: PropertyFilterProps.Query, queryB: PropertyFilterProps.Query) {
return (
queryA.operation === queryB.operation &&
queryA.tokens.length === queryB.tokens.length &&
queryA.tokens.every((_, i) => {
return (
queryA.tokens[i].operator === queryB.tokens[i].operator &&
queryA.tokens[i].value === queryB.tokens[i].value &&
queryA.tokens[i].propertyKey === queryB.tokens[i].propertyKey
);
})
);
return isEqual(queryA, queryB);
}

export function useFilterSets({
Expand Down Expand Up @@ -89,10 +84,10 @@ export function useFilterSets({
: filterSetOptions.find(({ value }) => value === selectedFilterSetValue) ?? null;

useEffect(() => {
const hasFilters = query.tokens.length > 0;
const hasFilters = !isQueryEmpty(query);

// Reset everything if there are no filters
if (query.tokens.length === 0) {
if (!hasFilters) {
setHasUnsavedChanges(false);
setCurrentFilterSet(null);
setSelectedFilterSetValue(null);
Expand Down
3 changes: 2 additions & 1 deletion src/styles/table-date-filter.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
grid-template-columns: auto;
gap: cs.$space-scaled-s;
}

@media (min-width: 688px) {
.date-time-form {
grid-template-columns: min-content minmax(100px, max-content);
grid-template-columns: repeat(2, minmax(100px, max-content));
}
}
19 changes: 17 additions & 2 deletions test/e2e/table-saved-filters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import TableSavedFiltersPageObject from './page/table-saved-filters-page-object'
import commonTableTests from './common/table/table-tests';
import commonPropertyFilteringTests from './common/table/table-property-filtering-tests';
import commonPreferencesTests from './common/table/table-preferences-tests';
import createWrapper from '@cloudscape-design/board-components/test-utils/selectors';

describe('Table - Saved Filters', () => {
const setupTest = (testFn: { (page: TableSavedFiltersPageObject): Promise<void> }) => {
Expand All @@ -21,9 +22,9 @@ describe('Table - Saved Filters', () => {
commonPropertyFilteringTests(setupTest);

test(
'Has two default saved filter sets',
'Has three default saved filter sets',
setupTest(async page => {
await expect(page.countSavedFilterSets()).resolves.toBe(2);
await expect(page.countSavedFilterSets()).resolves.toBe(3);
})
);

Expand Down Expand Up @@ -140,4 +141,18 @@ describe('Table - Saved Filters', () => {
await expect(page.getSelectedFilterSet()).resolves.toBe('Choose a filter set');
})
);

test(
'Parses filter set with groups correctly',
setupTest(async page => {
await page.selectSavedFilterSet(3);
await expect(page.countTokens()).resolves.toBe(2);
await expect(page.getSelectedFilterSet()).resolves.toBe('Best performance in buckets 1,2');

await page.openSaveFilterModal();
await expect(page.getText(createWrapper().findModal().toSelector())).resolves.toContain(
'(Origin = EXAMPLE-BUCKET-1.s3.amazon, or Origin = EXAMPLE-BUCKET-2.s3.amazon), and Price class = Use all edge locations (best performance)'
);
})
);
});
Loading