Building Better Filters: From Reusable Components to Customer Search
Authors:
Yulia Andreyanova, Alexey Kaminskiy
Changed on:
12 June 2025
Key Points
- This guide shows how to reuse filtering components designed for inventory management in other areas, using the Order List page as an example.
- The guide outlines integrating ready-made components such as Multi-Value Search for filtering by order references and enabling Customer Search with the new Complex Filter, backed by an extended orders query.

Prerequisites
Steps
Start with the Default Manifest
Begin by using the default manifest
`fc.mystique.manifest.oms.fragment.ordermanagement`
This guide will focus exclusively on the Orders menu item within the manifest, so the full fragment won’t be included here.
Refine the GraphQL Query
Use a GraphQL query tailored for this feature. Start with an existing query, but remove unnecessary fields to ensure simplicity and efficiency. Modify the query to support the customer input field. Make sure the
`$customer`
1query ($orders_first: Int, $customer: [SearchCustomerInput]) {
2 orders(first: $orders_first, customer: $customer) {
3 edges {
4 node {
5 id
6 ref
7 retailer {
8 id
9 tradingName
10 }
11 type
12 status
13 createdOn
14 totalPrice
15 items {
16 edges {
17 node {
18 quantity
19 currency
20 }
21 }
22 }
23 customer {
24 id
25 firstName
26 lastName
27 username
28 }
29 }
30 }
31 }
32}
Language: json
Name: Refined Query
Description:
This query fetches key details about orders, including retailer info, items, and customer data.
Configure the Filter Panel
After refining the query, set up the Filter Panel Component to enable advanced filtering options. The configuration guide provides detailed instructions on how to do this.Â
Key Optimizations:
- Exclude Unwanted Filters: Use the property to remove unnecessary fields, simplifying the filtering process.
`exclude`
1 "exclude": [
2 "eta",
3 "totalprice",
4 "price",
5 "totaltaxprice",
6 "currency",
7 "paidprice",
8 "quantity",
9 "retailerid",
10 "fulfilmentchoiceref",
11 "expirytime",
12 "deliverytype",
13 "updatedon",
14 "taxprice",
15 "taxtype",
16 "status",
17 "createdon"
18 ]
Language: plain_text
Name: Example: Using exclude to Remove Unnecessary Fields
Description:
This example excludes unused fields like
`eta`
`taxprice`
- Handle Duplicate Field Names: Fields like may appear in both orders and order items. Excluding
`status`
removes it from both. To avoid this, explicitly define filters using`status`
.`additionalFields`
- Override Filters for Custom Components: Some fields, like , may need custom configurations. Use the
`type`
property to define custom dropdown values. You can do this through the manifest by listing options or by creating a JSON setting at the ACCOUNT or RETAILER level. The examples below show both methods.`overrides`
1{
2 "component": "fc.filterPanel",
3 "props": {
4 "allowReadWriteUrlParams": true,
5 "overrides": {
6 "type": {
7 "component": "select",
8 "label": "Type",
9 "multiple": true,
10 "sortPrefix": 3,
11 "extensions": {
12 "hideDefaultValue": true
13 },
14 "options": [
15 {
16 "label": "HD",
17 "value": "HD"
18 },
19 {
20 "label": "CC",
21 "value": "CC"
22 }
23 ]
24 }
25 },
26 "additionalFields": [
27 {
28 "component": "select",
29 "props": {
30 "label": "Status",
31 "multiple": true,
32 "variableName": "orders_status",
33 "sortPrefix": 3,
34 "extensions": {
35 "hideDefaultValue": true
36 },
37 "options": [
38 {
39 "label": "BOOKED",
40 "value": "BOOKED"
41 },
42 {
43 "label": "PROCESSING",
44 "value": "PROCESSING"
45 }
46 ]
47 }
48 },
49 {
50 "component": "daterange",
51 "props": {
52 "label": "CreatedOn",
53 "sortPrefix": 5,
54 "variableName": "orders_createdOn"
55 }
56 }
57 ],
58 "exclude": [
59 "eta",
60 "totalprice",
61 "price",
62 "totaltaxprice",
63 "currency",
64 "paidprice",
65 "quantity",
66 "retailerid",
67 "fulfilmentchoiceref",
68 "expirytime",
69 "deliverytype",
70 "updatedon",
71 "ref",
72 "taxprice",
73 "taxtype",
74 "status",
75 "createdon"
76 ]
77 }
78}
Language: plain_text
Name: Defining Custom Dropdown Values in the Manifest
Description:
[Warning: empty required content area]1 {
2 "additionalFields": [
3 {
4 "component": "select",
5 "props": {
6 "label": "Status",
7 "multiple": true,
8 "variableName": "orders_status",
9 "sortPrefix": 3,
10 "extensions": {
11 "hideDefaultValue": true,
12 "source": "fc.oms.mystique.order.search.statuses"
13 }
14 }
15 },
16 {
17 "component": "daterange",
18 "props": {
19 "label": "CreatedOn",
20 "sortPrefix": 5,
21 "variableName": "orders_createdOn"
22 }
23 }
24 ]
25}
Language: json
Name: Defining Fields for Filtering via a Setting
Description:
[Warning: empty required content area]
Search Orders by Customer Name, Email, or Phone
Customer filtering on the Order List can be configured in two ways, depending on the level of flexibility and UX required.
Option 1: Complex Filter Component (Recommended for advanced use cases)
Use a Complex Filter Component to enable flexible search by customer fields such as
`username`
`firstName`
`lastName`
`primaryEmail`
`primaryPhone`
The component connects to the
`customers`
`customer`
`SearchCustomerInput`
It supports dynamic rendering of selected users as chips and configurable card views for search results, and hides irrelevant fields to keep the filter UI clean and focused.
1{
2 "component": "fc.field.filterComplex",
3 "props": {
4 "label": "Customer",
5 "variableName": "customer",
6 "sortPrefix": 5,
7 "outputTemplate": "{\"username\": \"{{value}}\"}",
8 "inputTemplate": "{{username}}",
9 "extensions": {
10 "filtersSource": "customers",
11 "query": "query customers($customers_first: Int) { customers(first: $customers_first) { edges { node { id username ref primaryPhone primaryEmail firstName lastName } } } }",
12 "variables": {
13 "customers_first": 100
14 },
15 "overrides": {
16 "firstName": {
17 "component": "fc.field.multistring",
18 "sortPrefix": 1
19 }
20 },
21 "searchItemConfig": {
22 "component": "fc.card.product",
23 "props": {
24 "title": "{{node.username}}",
25 "attributes": [
26 { "value": "{{node.firstName}} {{node.lastName}}" },
27 { "value": "{{node.primaryPhone}}" },
28 { "value": "{{node.primaryEmail}}" }
29 ]
30 }
31 },
32 "chipItemConfig": {
33 "label": "{{node.firstName}} {{node.lastName}}"
34 },
35 "onChangeValues": {
36 "value": "node.username",
37 "variableName": "customer"
38 },
39 "exclude": [
40 "updatedon", "status", "createdon", "department",
41 "title", "country", "timeZone", "promotionOptIn"
42 ]
43 }
44 }
45}
Language: plain_text
Name: Configure Complex Customer Filter
Description:
Adds customer search to the order filter using the flexible
`SearchCustomerInput`
Use this configuration in the
`additionalFields`
Option 2: Basic Filter Fields
Use the Multi-Value Search Component to add individual input fields to target nested variables such as
`customer.firstName`
`customer.lastName`
`additionalFields`
`fc.filterPanel`
1{
2 "manifestVersion": "2.0",
3 "routes": [
4 {
5 "type": "section",
6 "nav": {
7 "label": "i18n:fc.om.nav",
8 "icon": "shopping_cart"
9 },
10 "pages": [
11 {
12 "type": "page",
13 "path": "events",
14 "component": "fc.page",
15 "data": {
16 "query": "query ($orders_first: Int, $customer: [SearchCustomerInput]) { orders(first: $orders_first, customer: $customer) { edges { node {id ref retailer { id tradingName } type status createdOn totalPrice items {edges {node {quantity currency}}} customer {id firstName lastName username}}}}}",
17 "variables": {
18 "orders_first": 100
19 }
20 },
21 "nav": {
22 "label": "i18n:fc.om.orders.index.nav",
23 "icon": "library_books"
24 },
25 "props": {
26 "title": "i18n:fc.om.orders.index.title"
27 },
28 "descendants": [
29 {
30 "component": "fc.filterPanel",
31 "props": {
32 "allowReadWriteUrlParams": true,
33 "filtersSource": "orders",
34 "overrides": {
35 "status": {
36 "component": "select",
37 "label": "Status",
38 "multiple": true,
39 "sortPrefix": 3,
40 "extensions": {
41 "hideDefaultValue": true,
42 "source": "fc.oms.mystique.inventory.search.inventory.position.stock.statuses"
43 }
44 }
45 },
46 "additionalFields": [
47 {
48 "component": "fc.field.multistring",
49 "props": {
50 "label": "First Name",
51 "variableName": "customer.firstName",
52 "sortPrefix": 1
53 }
54 },
55 {
56 "component": "fc.filter.string",
57 "props": {
58 "label": "Last Name",
59 "variableName": "customer.lastName",
60 "sortPrefix": 2
61 }
62 }
63 ],
64 "exclude": [
65 "createdOn",
66 "currency",
67 "paidprice",
68 "price",
69 "productRef",
70 "ref",
71 "ref2",
72 "retailerid",
73 "tag1",
74 "tag2",
75 "tag3",
76 "taxprice",
77 "taxtype",
78 "totalprice",
79 "totaltaxprice",
80 "type",
81 "quantity",
82 "updatedon"
83 ]
84 }
85 },
86 {
87 "component": "fc.list",
88 "props": {
89 "defaultPageSize": 100,
90 "dataSource": "orders",
91 "responsiveness": "card",
92 "attributes": [
93 {
94 "label": "i18n:fc.om.orders.index.list.column.orderRef.heading",
95 "template": "{{node.ref}}",
96 "link": "#/orders/{{node.id}}/{{node.retailer.id}}/{{node.ref}}",
97 "condition": "{{and node.id node.retailer.id node.ref}}"
98 },
99 {
100 "label": "i18n:fc.om.orders.index.list.column.customer.heading",
101 "template": "{{node.customer.firstName}} {{node.customer.lastName}}"
102 },
103 {
104 "label": "i18n:fc.om.orders.index.list.column.orderType.heading",
105 "template": "{{node.type}}"
106 },
107 {
108 "label": "i18n:fc.om.orders.index.list.column.status.heading",
109 "type": "component",
110 "options": {
111 "component": "fc.attribute.column",
112 "props": {
113 "contentColumnSetting": "fc.order.list.status.column",
114 "value": "{{status}}"
115 },
116 "dataSource": "node"
117 }
118 },
119 {
120 "label": "i18n:fc.om.orders.index.list.column.orderValue.heading",
121 "template": "{{currency node.totalPrice node.items.edges.0.node.currency}}"
122 },
123 {
124 "label": "Total Order Items",
125 "value": "{{node.items.edges.length}}"
126 },
127 {
128 "label": "Total Order Item Qty",
129 "value": "{{arraySum node.items.edges 'node.quantity'}}"
130 },
131 {
132 "label": "i18n:fc.om.orders.index.list.column.createdOn.heading",
133 "template": "{{dateStringFormatter node.createdOn}} ({{dateRelative node.createdOn}})"
134 }
135 ]
136 }
137 }
138 ]
139 }
140 ]
141 }
142 ]
143}
Language: plain_text
Name: Basic Filter Fields Configuration
Description:
Configuration example
Use Multi-Value Search Component for Filtering by Order References
When users need to search for multiple order references at once, precision matters; the Multi-Value Search Component handles this well. Each input becomes a chip, duplicates are removed, and extra spaces are trimmed.
Below is how to configure the
`ref`
1 {
2 "overrides": {
3 "ref": {
4 "component": "fc.field.multistring",
5 "label": "Order Reference",
6 "exactSearch": true,
7 "visibleItemsThreshold": 3,
8 "sortPrefix": 3
9 }
10 }
11}
Language: plain_text
Name: Configure Multi-Value Order Reference Filter
Description:
Adds a filter field for exact match multi-reference lookup with chip display and auto-cleaning.
Use this in the
`fc.filterPanel`
`props.overrides`
Add the Grid with the Embedded Filter Panel
Use the standard List component for the grid. Configure the row setting of the
`fc.list`
- A separate query is executed to fetch an order by its ID and associated fulfillments for the selected order.
- Like the filter panel, exclude unnecessary fields and override others to match specific requirements. For fulfillment status and delivery type filters, either create JSON settings or define dropdown values through the manifest. In the example below, the options are set using ACCOUNT level JSON settings: and
`fc.oms.mystique.fulfilment.search.statuses`
.`fc.oms.mystique.fulfilment.search.delivery.types`
- The grid itself, also a component, is configured with a data source and attributes similar to those used for fulfillment on the Order Details Page.
`fc.list `
1{
2 "component": "fc.list",
3 "props": {
4 "defaultPageSize": 100,
5 "dataSource": "orders",
6 "responsiveness": "card",
7 "row": {
8 "expansion": {
9 "toggle": true,
10 "descendants": [
11 {
12 "component": "fc.filterPanel",
13 "props": {
14 "noCard": true,
15 "query": "query orderById($id: ID!) { orderById(id: $id) { fulfilments { edges { node { id status deliveryType createdOn fromAddress { ref companyName name } toAddress { ref companyName name } } } } } } }",
16 "variables": {
17 "id": "{{node.id}}"
18 },
19 "overrides": {
20 "status": {
21 "component": "select",
22 "label": "Status",
23 "multiple": true,
24 "sortPrefix": 3,
25 "extensions": {
26 "hideDefaultValue": true,
27 "source": "fc.oms.mystique.fulfilment.search.statuses"
28 }
29 },
30 "deliveryType": {
31 "component": "select",
32 "label": "Delivery Type",
33 "multiple": true,
34 "sortPrefix": 3,
35 "extensions": {
36 "hideDefaultValue": true,
37 "source": "fc.oms.mystique.fulfilment.search.delivery.types"
38 }
39 }
40 },
41 "exclude": ["ref", "fulfilmentchoiceref", "type", "eta", "updatedon", "expirytime", "retailerid"],
42 "descendants": [
43 {
44 "component": "fc.list",
45 "dataSource": "orderById.fulfilments",
46 "props": {
47 "attributes": [
48 {
49 "label": "i18n:fc.om.orders.detail.list.fulfilments.column.id.heading",
50 "template": "{{node.id}}",
51 "link_template": "#/fulfilment/{{node.id}}",
52 "condition": "{{and node.id}}"
53 },
54 {
55 "label": "i18n:fc.om.orders.detail.list.fulfilments.column.status.heading",
56 "template": "{{node.status}}"
57 },
58 {
59 "label": "i18n:fc.om.orders.detail.list.fulfilments.column.deliveryType.heading",
60 "template": "{{node.deliveryType}}"
61 },
62 {
63 "label": "i18n:fc.om.orders.detail.list.fulfilments.column.fulfilmentLocation.heading",
64 "template": "{{node.fromAddress.companyName}} {{#if node.fromAddress.name}}{{node.fromAddress.name}}{{/if}}"
65 },
66 {
67 "label": "i18n:fc.om.orders.detail.list.fulfilments.column.destination.heading",
68 "template": "{{node.toAddress.companyName}} {{node.toAddress.name}}"
69 },
70 {
71 "label": "i18n:fc.om.orders.detail.list.fulfilments.column.createdOn.heading",
72 "template": "{{dateStringFormatter node.createdOn}}"
73 }
74 ]
75 }
76 }
77 ]
78 }
79 }
80 ]
81 }
82 }
83 }
84}
Language: plain_text
Name: List Configuration Example
Description:
This grid displays orders with expandable rows that include filter panels for more options.
Final Step: Add the Fragment to the Main Manifest
After configuring the new fragment, add it to your main manifest.