diff --git a/examples/nuxt-app/test/features/landingpage/custom-collection.feature b/examples/nuxt-app/test/features/landingpage/custom-collection.feature index e0ffc52933..16b9334f40 100644 --- a/examples/nuxt-app/test/features/landingpage/custom-collection.feature +++ b/examples/nuxt-app/test/features/landingpage/custom-collection.feature @@ -32,6 +32,7 @@ Feature: Custom Collection Then the custom collection dropdown field labelled "Terms dependent example" should have the "default" variant applied Then the custom collection dropdown field labelled "Terms dependent child example" should have the "default" variant applied And the custom collection checkbox group labelled "Checkbox group" should have the "default" variant applied + And the custom collection date range field labelled "Date range example" should have the "default" variant applied @mockserver Scenario: Default page - reverse form theme @@ -47,6 +48,7 @@ Feature: Custom Collection Then the custom collection dropdown field labelled "Terms dependent example" should have the "reverse" variant applied Then the custom collection dropdown field labelled "Terms dependent child example" should have the "reverse" variant applied And the custom collection checkbox group labelled "Checkbox group" should have the "reverse" variant applied + And the custom collection date range field labelled "Date range example" should have the "reverse" variant applied @mockserver Scenario: Alt page - default form theme @@ -62,6 +64,7 @@ Feature: Custom Collection Then the custom collection dropdown field labelled "Terms dependent example" should have the "reverse" variant applied Then the custom collection dropdown field labelled "Terms dependent child example" should have the "reverse" variant applied And the custom collection checkbox group labelled "Checkbox group" should have the "reverse" variant applied + And the custom collection date range field labelled "Date range example" should have the "reverse" variant applied @mockserver Scenario: Alt page - reverse form theme @@ -77,6 +80,7 @@ Feature: Custom Collection Then the custom collection dropdown field labelled "Terms dependent example" should have the "default" variant applied Then the custom collection dropdown field labelled "Terms dependent child example" should have the "default" variant applied And the custom collection checkbox group labelled "Checkbox group" should have the "default" variant applied + And the custom collection date range field labelled "Date range example" should have the "default" variant applied @mockserver Scenario: Error diff --git a/examples/nuxt-app/test/features/search-listing/events.feature b/examples/nuxt-app/test/features/search-listing/events.feature index b95c6df974..fe27a24175 100644 --- a/examples/nuxt-app/test/features/search-listing/events.feature +++ b/examples/nuxt-app/test/features/search-listing/events.feature @@ -8,7 +8,7 @@ Feature: Events collection Given the page endpoint for path "/events" returns fixture "/search-listing/events/page" with status 200 And the search network request is stubbed with fixture "/search-listing/events/response" and status 200 When I visit the page "/events" - Then the search listing page should have 2 results + Then the search listing page should have 4 results And the search listing layout should be "grid" And the search network request should be called with the "/search-listing/events/request" fixture And the event search listing results should have following items: diff --git a/examples/nuxt-app/test/features/search-listing/filters.feature b/examples/nuxt-app/test/features/search-listing/filters.feature index 1584832449..24cea2d7a8 100644 --- a/examples/nuxt-app/test/features/search-listing/filters.feature +++ b/examples/nuxt-app/test/features/search-listing/filters.feature @@ -101,6 +101,62 @@ Feature: Search listing - Filter When I toggle the search listing filters section Then the search listing dropdown field labelled "Terms filter example" should have the value "Orange, Purple" + @mockserver + Example: Date range filter (single query value) - Should reflect the range value from the URL + Given the page endpoint for path "/filters" returns fixture "/search-listing/filters/page" with status 200 + And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200 + + When I visit the page "/filters?dateRangeFilter=from:2024-10-01&dateRangeFilter=to:2025-06-28" + And the search network request should be called with the "/search-listing/filters/request-date-range" fixture + Then the filters toggle should show 1 applied filters + + When I toggle the search listing filters section + Then the search listing date range field labelled "Date range example" should have the values + | from | to | + | 2024-10-01 | 2025-06-28 | + + @mockserver + Example: Date range filter (query range matches start and end date) - Should correctly query search API + Given the page endpoint for path "/filters" returns fixture "/search-listing/events/page" with status 200 + And the search network request is stubbed with fixture "/search-listing/events/response" and status 200 + + When I visit the page "/filters?dateRangeFilter=from:2024-10-01&dateRangeFilter=to:2025-06-28" + And the search network request should be called with the "/search-listing/events/request-date-range" fixture + Then the filters toggle should show 1 applied filters + + When I toggle the search listing filters section + Then the search listing date range field labelled "Date range example" should have the values + | from | to | + | 2024-10-01 | 2025-06-28 | + + @mockserver + Example: Date range filter (query range matches start date) - Should correctly query search API + Given the page endpoint for path "/filters" returns fixture "/search-listing/events/page" with status 200 + And the search network request is stubbed with fixture "/search-listing/events/response" and status 200 + + When I visit the page "/filters?dateRangeFilter=from:2024-10-01" + And the search network request should be called with the "/search-listing/events/request-date-range-start" fixture + Then the filters toggle should show 1 applied filters + + When I toggle the search listing filters section + Then the search listing date range field labelled "Date range example" should have the values + | from | to | + | 2024-10-01 | | + + @mockserver + Example: Date range filter (query range matches end date) - Should correctly query search API + Given the page endpoint for path "/filters" returns fixture "/search-listing/events/page" with status 200 + And the search network request is stubbed with fixture "/search-listing/events/response" and status 200 + + When I visit the page "/filters?dateRangeFilter=to:2025-06-28" + And the search network request should be called with the "/search-listing/events/request-date-range-end" fixture + Then the filters toggle should show 1 applied filters + + When I toggle the search listing filters section + Then the search listing date range field labelled "Date range example" should have the values + | from | to | + | | 2025-06-28 | + @mockserver Example: Custom function filters - Should reflect an array from the URL Given the page endpoint for path "/filters" returns fixture "/search-listing/filters/page" with status 200 @@ -131,11 +187,11 @@ Feature: Search listing - Filter And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200 And the current date is "Fri, 02 Feb 2050 03:04:05 GMT" - When I visit the page "/filters?q=test123&page=2&functionFilter=open&termsFilter=Purple&termFilter=Green&rawFilter=Birds&checkboxFilter=Archived&checkboxFilterGroup=Weekdays" + When I visit the page "/filters?q=test123&page=2&functionFilter=open&termsFilter=Purple&termFilter=Green&rawFilter=Birds&checkboxFilter=Archived&checkboxFilterGroup=Weekdays&dateRangeFilter=from:2024-10-01&dateRangeFilter=to:2025-06-28" Then the search listing page should have 2 results And the search network request should be called with the "/search-listing/filters/request-clear-filled" fixture - Then the filters toggle should show 6 applied filters + Then the filters toggle should show 7 applied filters Then the URL should reflect that the current page number is 2 Then the URL should reflect that the current search term is "test123" @@ -149,6 +205,9 @@ Feature: Search listing - Filter | functionFilter | open | | checkboxFilter | Archived | | checkboxFilterGroup | Weekdays | + And the URL should reflect that the current active filters are as follows: + | dateRangeFilter | from:2024-10-01 | + | dateRangeFilter | to:2025-06-28 | Then the search listing dropdown field labelled "Raw filter example" should have the value "Birds" Then the search listing dropdown field labelled "Term filter example" should have the value "Green" @@ -169,6 +228,7 @@ Feature: Search listing - Filter | functionFilter | | checkboxFilter | | checkboxFilterGroup | + | dateRangeFilter | Then the search input should have the value "" Then the search listing dropdown field labelled "Raw filter example" should have the value "Select a pet" @@ -177,6 +237,9 @@ Feature: Search listing - Filter Then the search listing dropdown field labelled "Custom function filter example" should have the value "Select a status" And the search listing checkbox field labelled "Show archived content" should not be checked And the search listing checkbox group labelled "Checkbox group" should not have any options checked + And the search listing date range field labelled "Date range example" should have the values + | from | to | + | | | @mockserver Example: Should update the URL when the filters are applied @@ -373,6 +436,19 @@ Feature: Search listing - Filter And I click the search listing dropdown field labelled "Terms dependent grandchild example" Then the selected dropdown field should allow "multi" selection + @mockserver + Example: Date range filter query can be customised with user options + Given the page endpoint for path "/filters" returns fixture "/search-listing/filters/page-date-range" with status 200 + And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200 + + When I visit the page "/filters?dateRangeFilter=from:2024/10/01" + And the search network request should be called with the "/search-listing/filters/request-date-range-custom" fixture + + When I toggle the search listing filters section + Then the search listing date range field labelled "Date range example" should have the values + | from | to | + | 2024-10-01 | | + @mockserver Example: Should hide the search form when hideSearchForm is set Given the page endpoint for path "/no-search-form" returns fixture "/search-listing/filters/page-no-search-form" with status 200 diff --git a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-default.json b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-default.json index b7a4ae4a94..d0d83bd8f2 100644 --- a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-default.json +++ b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-default.json @@ -180,6 +180,23 @@ } ] } + }, + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": "changed", + "multiple": false, + "countAsSingle": true, + "valueIsObject": true + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example", + "min": "2024-07-01", + "max": "2084-06-30" + } } ], "resultsConfig": { diff --git a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-reverse.json b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-reverse.json index 278c3fd809..1cec0c16cc 100644 --- a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-reverse.json +++ b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/alt-form-theme-reverse.json @@ -180,6 +180,23 @@ } ] } + }, + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": "changed", + "multiple": false, + "countAsSingle": true, + "valueIsObject": true + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example", + "min": "2024-07-01", + "max": "2084-06-30" + } } ], "resultsConfig": { diff --git a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-default.json b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-default.json index de25caf77c..483c5b386b 100644 --- a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-default.json +++ b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-default.json @@ -180,6 +180,23 @@ } ] } + }, + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": "changed", + "multiple": false, + "countAsSingle": true, + "valueIsObject": true + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example", + "min": "2024-07-01", + "max": "2084-06-30" + } } ], "resultsConfig": { diff --git a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-reverse.json b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-reverse.json index 429ebe6659..bf5d109ecf 100644 --- a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-reverse.json +++ b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/form-theme-reverse.json @@ -180,6 +180,23 @@ } ] } + }, + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": "changed", + "multiple": false, + "countAsSingle": true, + "valueIsObject": true + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example", + "min": "2024-07-01", + "max": "2084-06-30" + } } ], "resultsConfig": { diff --git a/examples/nuxt-app/test/fixtures/search-listing/events/page.json b/examples/nuxt-app/test/fixtures/search-listing/events/page.json index 3e3ab4f95b..afc6fc63fb 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/events/page.json +++ b/examples/nuxt-app/test/fixtures/search-listing/events/page.json @@ -114,6 +114,24 @@ "label": "Event date", "type": "RplFormDate" } + }, + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": { + "start": "field_event_date_start_value", + "end": "field_event_date_end_value" + }, + "multiple": false, + "countAsSingle": true, + "valueIsObject": true + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example" + } } ] }, diff --git a/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range-end.json b/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range-end.json new file mode 100644 index 0000000000..e06e3c0efb --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range-end.json @@ -0,0 +1,42 @@ +{ + "query": { + "bool": { + "must": [ + { + "match_all": {} + } + ], + "filter": [ + { + "terms": { + "type": [ + "event" + ] + } + }, + { + "terms": { + "field_node_site": [ + 4 + ] + } + }, + { + "range": { + "field_event_date_start_value": { + "lte": "2025-06-28", + "time_zone": "Australia/Melbourne" + } + } + } + ] + } + }, + "size": 9, + "from": 0, + "sort": [ + { + "field_event_date_end_value": "asc" + } + ] +} diff --git a/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range-start.json b/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range-start.json new file mode 100644 index 0000000000..3c41e34af2 --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range-start.json @@ -0,0 +1,42 @@ +{ + "query": { + "bool": { + "must": [ + { + "match_all": {} + } + ], + "filter": [ + { + "terms": { + "type": [ + "event" + ] + } + }, + { + "terms": { + "field_node_site": [ + 4 + ] + } + }, + { + "range": { + "field_event_date_end_value": { + "gte": "2024-10-01", + "time_zone": "Australia/Melbourne" + } + } + } + ] + } + }, + "size": 9, + "from": 0, + "sort": [ + { + "field_event_date_end_value": "asc" + } + ] +} diff --git a/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range.json b/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range.json new file mode 100644 index 0000000000..22893f24ea --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/events/request-date-range.json @@ -0,0 +1,50 @@ +{ + "query": { + "bool": { + "must": [ + { + "match_all": {} + } + ], + "filter": [ + { + "terms": { + "type": [ + "event" + ] + } + }, + { + "terms": { + "field_node_site": [ + 4 + ] + } + }, + { + "range": { + "field_event_date_end_value": { + "gte": "2024-10-01", + "time_zone": "Australia/Melbourne" + } + } + }, + { + "range": { + "field_event_date_start_value": { + "lte": "2025-06-28", + "time_zone": "Australia/Melbourne" + } + } + } + ] + } + }, + "size": 9, + "from": 0, + "sort": [ + { + "field_event_date_end_value": "asc" + } + ] +} diff --git a/examples/nuxt-app/test/fixtures/search-listing/events/response.json b/examples/nuxt-app/test/fixtures/search-listing/events/response.json index 22024256f2..2b02902e37 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/events/response.json +++ b/examples/nuxt-app/test/fixtures/search-listing/events/response.json @@ -253,6 +253,150 @@ "sort": [ 1679203800000 ] + }, + { + "_index": "b56de58036ae7d6456d5b246f85ffe88--elasticsearch_index_develop_node", + "_id": "entity:node/182:en", + "_score": null, + "_ignored": ["body.keyword"], + "_source": { + "_language": "en", + "node_grants": ["node_access_all:0", "node_access_all:0"], + "url": [ + "/site-9210/roulette-aerial-display-demo", + "/site-8888/roulette-aerial-display-demo", + "/site-9012/roulette-aerial-display-demo", + "/site-9170/roulette-aerial-display-demo", + "/site-9205/roulette-aerial-display-demo" + ], + "body": [ + "The Air Force Roulettes will conduct a flypast of Melbourne CBD on Australia Day at 12.30pm. Following this flypast, the Roulettes will conduct an aerobatic display over Kings Domain Gardens and the Shrine of Remembrance. Throughout the flypasts and displays, the Roulettes will be flying as low as 250 feet (80 metres), at speeds up to 540km/h, and experiencing up to 6 times the force of gravity in their PC-21 aircraft. All flying is subject to change due to weather and operational requirements." + ], + "changed": ["2024-10-03T14:34:37+10:00"], + "created": ["2024-10-03T14:34:37+10:00"], + "field_event_category_name": ["Demo Event Category"], + "field_event_category_tid": [9236], + "field_event_category_uuid": [ + "11dede11-10c0-111e1-1099-000000000050" + ], + "field_event_date_end_value": [ + "2023-06-01T14:30:00+11:00" + ], + "field_event_date_start_value": [ + "2023-08-28T10:30:00+11:00" + ], + "field_event_details_event_address_1": ["Melbourne CBD"], + "field_event_details_event_address_line2": [""], + "field_event_details_event_administrative_area": ["VIC"], + "field_event_details_event_locality": ["Melbourne"], + "field_event_details_event_postal_code": ["3000"], + "field_event_details_event_price_from": ["Free entry"], + "field_event_details_event_price_to": ["0"], + "field_event_intro_text": [ + "Air Force Roulettes at Australia Day in Victoria." + ], + "field_landing_page_summary": [ + "Air Force Roulettes at Australia Day in Victoria." + ], + "field_media_image_absolute_path": [ + "https://develop.content.reference.sdp.vic.gov.au/sites/default/files/tide_demo_content/roulette-aerial-display-card.jpg" + ], + "field_node_site": [9210, 9211, 9212, 8888, 9012, 9170, 9205], + "field_tags": [9187, 9186], + "field_tags_name": ["Gen X tag demo", "Boomers tag demo"], + "field_tags_path": ["/tags/gen-x-tag-demo", "/tags/boomers-tag-demo"], + "field_tags_uuid": [ + "11dede11-10c0-111e1-1101-000000000017", + "11dede11-10c0-111e1-1101-000000000016" + ], + "field_topic": [9198], + "field_topic_name": ["Spencer topic demo"], + "field_topic_path": ["/topic/spencer-topic-demo"], + "field_topic_uuid": ["11dede11-10c0-111e1-1102-000000000026"], + "langcode": ["en"], + "nid": [182], + "status": [true], + "title": ["Roulette Aerial Display - demo"], + "type": ["event"], + "uid": [1], + "uuid": ["d9f0aa89-4350-46e6-8d94-6664110c0a9e"] + }, + "sort": [1727930077000] + }, + { + "_index": "b56de58036ae7d6456d5b246f85ffe88--elasticsearch_index_develop_node", + "_id": "entity:node/178:en", + "_score": null, + "_ignored": ["field_event_description.keyword", "body.keyword"], + "_source": { + "_language": "en", + "node_grants": ["node_access_all:0", "node_access_all:0"], + "url": [ + "/site-8888/demo-event", + "/site-9205/demo-event", + "/site-9012/demo-event", + "/site-9170/demo-event", + "/site-9210/demo-event" + ], + "body": [ + "Nulla ultricies dignissim leo, posuere vestibulum erat cursus vitae Phasellus congue aliquam vehicula Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sit amet ligula sit amet lacinia. In a leo nec tortor aliquet faucibus. Quisque nec congue ligula, vitae condimentum tellus. Nulla nec urna augue. Curabitur commodo nisi est, eu pulvinar tortor cursus vel. Morbi dictum ex est, et semper diam finibus eu. Cras rutrum, nunc a fringilla convallis, massa est vulputate velit, in blandit augue dui vitae elit. Donec hendrerit commodo augue, in maximus orci tempor congue. Mauris ultricies euismod orci, nec vehicula quam vehicula ac. Nunc dictum tortor dolor, nec eleifend orci luctus sed. Donec scelerisque cursus ex varius efficitur Morbi cursus placerat mi Nullam laoreet ante placerat Integer interdum nisl ut neque dictum, et sagittis metus feugiat. Sed in mattis neque. Duis at risus non ipsum semper dapibus. Sed enim sapien, molestie sed commodo vel, lacinia vitae risus. Proin sagittis diam nisi, sed rhoncus diam varius id. Sed malesuada felis tortor, scelerisque pretium elit tempor non. Pellentesque ultrices volutpat tincidunt. Fusce quis viverra urna, quis finibus nulla. Mauris tincidunt tincidunt felis vel tempus. Vestibulum rhoncus blandit justo quis finibus. Phasellus lacus lectus, sollicitudin sed posuere non, ultricies ut quam. Duis ligula lacus Phasellus est turpis, efficitur nec odio imperdiet Mauris tincidunt tincidunt felis vel tempus Phasellus in varius leo. Suspendisse potenti. Donec scelerisque cursus ex varius efficitur. Vivamus pretium nisi sed libero accumsan mattis. Duis convallis, velit eget varius tempus, orci erat aliquam sem, eget porta mauris nisl at mauris." + ], + "changed": ["2024-10-03T14:34:37+10:00"], + "created": ["2024-10-03T14:34:37+10:00"], + "field_event_category_name": ["Demo Event Category"], + "field_event_category_tid": [9236], + "field_event_category_uuid": [ + "11dede11-10c0-111e1-1099-000000000050" + ], + "field_event_date_end_value": [ + "2023-07-12T14:30:00+11:00" + ], + "field_event_date_start_value": [ + "2023-12-02T10:30:00+11:00" + ], + "field_event_description": [ + "Integer interdum nisl ut neque dictum, et sagittis metus feugiat. Sed in mattis neque. Duis at risus non ipsum semper dapibus. Sed enim sapien, molestie sed commodo vel, lacinia vitae risus. Proin sagittis diam nisi, sed rhoncus diam varius id. Sed malesuada felis tortor, scelerisque pretium elit tempor non. Pellentesque ultrices volutpat tincidunt. Fusce quis viverra urna, quis finibus nulla." + ], + "field_event_details_event_address_1": [ + "Department of Premier and Cabinet" + ], + "field_event_details_event_address_line2": ["GPO Box 4509"], + "field_event_details_event_administrative_area": ["VIC"], + "field_event_details_event_locality": ["Melbourne"], + "field_event_details_event_postal_code": ["3001"], + "field_event_details_event_price_from": ["Free entry"], + "field_event_details_event_price_to": ["0"], + "field_event_intro_text": [ + "Nulla ultricies dignissim leo, posuere vestibulum erat cursus vitae" + ], + "field_landing_page_contact_name": ["Victorian Government"], + "field_landing_page_summary": [ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sit amet ligula sit amet lacinia. In a leo nec tortor aliquet faucibus." + ], + "field_media_image_absolute_path": [ + "https://develop.content.reference.sdp.vic.gov.au/sites/default/files/tide_demo_content/Demo-tram.jpg" + ], + "field_node_site": [8888, 9203, 9205, 9012, 9170, 9210], + "field_tags": [9180, 9181], + "field_tags_name": ["Demo Tag", "Another Demo Tag"], + "field_tags_path": ["/tags/demo-tag", "/tags/another-demo-tag"], + "field_tags_uuid": [ + "11dede11-10c0-111e1-1101-000000000010", + "11dede11-10c0-111e1-1101-000000000011" + ], + "field_topic": [9192], + "field_topic_name": ["Demo Topic"], + "field_topic_path": ["/topic/demo-topic"], + "field_topic_uuid": ["11dede11-10c0-111e1-1102-000000000020"], + "langcode": ["en"], + "nid": [178], + "status": [true], + "title": ["Demo Event"], + "type": ["event"], + "uid": [1], + "uuid": ["11dede11-10c0-111e1-1100-000000000310"] + }, + "sort": [1727930077000] } ] } diff --git a/examples/nuxt-app/test/fixtures/search-listing/filters/page-date-range.json b/examples/nuxt-app/test/fixtures/search-listing/filters/page-date-range.json new file mode 100644 index 0000000000..df40ccae46 --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/filters/page-date-range.json @@ -0,0 +1,62 @@ +{ + "title": "Date range", + "changed": "2022-11-02T12:47:29+11:00", + "created": "2022-11-02T12:47:29+11:00", + "type": "tide_search_listing", + "nid": "11dede11-10c0-111e1-1100-000000000330", + "showTopicTags": true, + "summary": "", + "config": { + "searchListingConfig": { + "resultsPerPage": 10 + }, + "queryConfig": { + "multi_match": { + "query": "{{query}}", + "fields": [ + "title^3", + "field_landing_page_summary^2", + "body", + "field_paragraph_body", + "summary_processed" + ] + } + }, + "results": { + "layout": { + "component": "TideSearchResultsList" + }, + "item": { + "grant": { + "component": "TideGrantSearchResult" + } + } + }, + "globalFilters": [ + { "terms": { "type": ["grant"] } }, + { "terms": { "field_node_site": [8888] } } + ], + "userFilters": [ + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": "changed", + "multiple": false, + "countAsSingle": true, + "valueIsObject": true, + "relation": "CONTAINS", + "format": "yyyy/mm/dd" + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example", + "dateFormat": "yyyy/mm/dd", + "min": "2024-07-01", + "max": "2084-06-30" + } + } + ] + } +} diff --git a/examples/nuxt-app/test/fixtures/search-listing/filters/page.json b/examples/nuxt-app/test/fixtures/search-listing/filters/page.json index ec3b967506..4c552b05ea 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/filters/page.json +++ b/examples/nuxt-app/test/fixtures/search-listing/filters/page.json @@ -244,6 +244,23 @@ } ] } + }, + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": "changed", + "multiple": false, + "countAsSingle": true, + "valueIsObject": true + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example", + "min": "2024-07-01", + "max": "2084-06-30" + } } ] } diff --git a/examples/nuxt-app/test/fixtures/search-listing/filters/request-clear-filled.json b/examples/nuxt-app/test/fixtures/search-listing/filters/request-clear-filled.json index c22bdde960..2456277b9b 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/filters/request-clear-filled.json +++ b/examples/nuxt-app/test/fixtures/search-listing/filters/request-clear-filled.json @@ -24,6 +24,15 @@ "field_node_site": [8888] } }, + { + "range": { + "changed": { + "time_zone": "Australia/Melbourne", + "gte": "2024-10-01", + "lte": "2025-06-28" + } + } + }, { "providedFilterConfig": { "id": "functionFilter", diff --git a/examples/nuxt-app/test/fixtures/search-listing/filters/request-date-range-custom.json b/examples/nuxt-app/test/fixtures/search-listing/filters/request-date-range-custom.json new file mode 100644 index 0000000000..a8c5cf6bde --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/filters/request-date-range-custom.json @@ -0,0 +1,42 @@ +{ + "query": { + "bool": { + "must": [ + { + "match_all": {} + } + ], + "filter": [ + { + "terms": { + "type": ["grant"] + } + }, + { + "terms": { + "field_node_site": [8888] + } + }, + { + "range": { + "changed": { + "time_zone": "Australia/Melbourne", + "gte": "2024/10/01", + "format": "yyyy/mm/dd" + } + } + } + ] + } + }, + "size": 10, + "from": 0, + "sort": [ + { + "_score": "desc" + }, + { + "_doc": "desc" + } + ] +} diff --git a/examples/nuxt-app/test/fixtures/search-listing/filters/request-date-range.json b/examples/nuxt-app/test/fixtures/search-listing/filters/request-date-range.json new file mode 100644 index 0000000000..dc6f8b7cbb --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/filters/request-date-range.json @@ -0,0 +1,46 @@ +{ + "query": { + "bool": { + "must": [ + { + "match_all": {} + } + ], + "filter": [ + { + "terms": { + "type": [ + "grant" + ] + } + }, + { + "terms": { + "field_node_site": [ + 8888 + ] + } + }, + { + "range": { + "changed": { + "time_zone": "Australia/Melbourne", + "gte": "2024-10-01", + "lte": "2025-06-28" + } + } + } + ] + } + }, + "size": 10, + "from": 0, + "sort": [ + { + "_score": "desc" + }, + { + "_doc": "desc" + } + ] +} diff --git a/packages/nuxt-ripple-analytics/lib/index.ts b/packages/nuxt-ripple-analytics/lib/index.ts index 5116a65567..07c9825840 100644 --- a/packages/nuxt-ripple-analytics/lib/index.ts +++ b/packages/nuxt-ripple-analytics/lib/index.ts @@ -667,6 +667,21 @@ export default { }) } }, + 'rpl-form-date-range/update': () => { + return (payload: any) => { + trackEvent({ + event: `${payload.action}_form_field`, + label: payload?.label, + form_name: payload?.contextName, + form_id: payload?.contextId, + field_id: payload?.id, + value: payload?.value, + type: 'date', + component: 'rpl-form-date-range', + platform_event: 'update' + }) + } + }, 'rpl-form-dropdown/toggleOpen': () => { return (payload: any) => { trackEvent({ diff --git a/packages/ripple-test-utils/step_definitions/components/custom-collection.ts b/packages/ripple-test-utils/step_definitions/components/custom-collection.ts index 942460b8d8..5e5aef64ae 100644 --- a/packages/ripple-test-utils/step_definitions/components/custom-collection.ts +++ b/packages/ripple-test-utils/step_definitions/components/custom-collection.ts @@ -72,6 +72,19 @@ Then( } ) +Then( + `the custom collection date range field labelled {string} should have the {string} variant applied`, + (label: string, theme: string) => { + cy.get(`legend`) + .contains(label) + .closest('fieldset') + .find('.rpl-form__input') + .each(($el) => { + cy.wrap($el).should('have.class', `rpl-form__input--${theme}`) + }) + } +) + Then( `the custom collection dropdown field labelled {string} should have the {string} variant applied`, (label: string, theme: string) => { diff --git a/packages/ripple-test-utils/step_definitions/content-types/listing.ts b/packages/ripple-test-utils/step_definitions/content-types/listing.ts index 443dbb75f7..5345e354b2 100644 --- a/packages/ripple-test-utils/step_definitions/content-types/listing.ts +++ b/packages/ripple-test-utils/step_definitions/content-types/listing.ts @@ -300,6 +300,24 @@ Then( } ) +Then( + `the search listing date range field labelled {string} should have the values`, + (label: string, dataTable: DataTable) => { + const table = dataTable.hashes() + + cy.get(`legend`) + .contains(label) + .closest('fieldset') + .find('input') + .as('dates') + + table.forEach((row) => { + cy.get('@dates').eq(0).should('have.value', row.from) + cy.get('@dates').eq(1).should('have.value', row.to) + }) + } +) + When( `I click the search listing checkbox field labelled {string}`, (label: string) => { diff --git a/packages/ripple-tide-search/components/TideSearchListingPage.vue b/packages/ripple-tide-search/components/TideSearchListingPage.vue index bbd62df036..110a9b7c01 100644 --- a/packages/ripple-tide-search/components/TideSearchListingPage.vue +++ b/packages/ripple-tide-search/components/TideSearchListingPage.vue @@ -332,7 +332,7 @@ const handleToggleFilters = () => { } const numAppliedFilters = computed(() => { - return getActiveFiltersTally(appliedFilters.value) + return getActiveFiltersTally(appliedFilters.value, props.userFilters) }) const toggleFiltersLabel = computed(() => { diff --git a/packages/ripple-tide-search/components/global/TideCustomCollection.vue b/packages/ripple-tide-search/components/global/TideCustomCollection.vue index a4aac77550..b2e85ad3cd 100644 --- a/packages/ripple-tide-search/components/global/TideCustomCollection.vue +++ b/packages/ripple-tide-search/components/global/TideCustomCollection.vue @@ -443,7 +443,7 @@ const handleToggleFilters = () => { } const numAppliedFilters = computed(() => { - return getActiveFiltersTally(appliedFilters.value) + return getActiveFiltersTally(appliedFilters.value, props.userFilters) }) const toggleFiltersLabel = computed(() => { diff --git a/packages/ripple-tide-search/components/global/TideSearchFilterDatePicker.vue b/packages/ripple-tide-search/components/global/TideSearchFilterDatePicker.vue index 99099ac34d..6eba9c390f 100644 --- a/packages/ripple-tide-search/components/global/TideSearchFilterDatePicker.vue +++ b/packages/ripple-tide-search/components/global/TideSearchFilterDatePicker.vue @@ -17,5 +17,6 @@ defineProps() type="RplFormDatePicker" :variant="variant" :label="label" + :pii="false" /> diff --git a/packages/ripple-tide-search/components/global/TideSearchFilterDateRange.vue b/packages/ripple-tide-search/components/global/TideSearchFilterDateRange.vue new file mode 100644 index 0000000000..f7db31748f --- /dev/null +++ b/packages/ripple-tide-search/components/global/TideSearchFilterDateRange.vue @@ -0,0 +1,22 @@ + + + diff --git a/packages/ripple-tide-search/composables/useTideSearch.ts b/packages/ripple-tide-search/composables/useTideSearch.ts index 0ba24117ff..6f2bac35d8 100644 --- a/packages/ripple-tide-search/composables/useTideSearch.ts +++ b/packages/ripple-tide-search/composables/useTideSearch.ts @@ -10,7 +10,11 @@ import { getSingleQueryStringValue, scrollToElementTopWithOffset } from '#imports' -import type { TideSearchListingConfig, FilterConfigItem } from './../types' +import type { + TideSearchListingConfig, + FilterConfigItem, + TideSearchRangeFilter +} from './../types' const escapeJSONString = (raw: string): string => { return `${raw}` @@ -284,7 +288,7 @@ export default ({ return !!itm?.filter }) - .map((key: string) => { + .flatMap((key: string) => { const itm: FilterConfigItem = userFilterConfig.find( (itm: any) => itm.id === key ) @@ -303,6 +307,15 @@ export default ({ ) { return Array.isArray(v) && v.length > 0 } + + if ( + itm?.filter?.valueIsObject && + typeof v === 'object' && + v !== null + ) { + return Object.keys(v).length + } + return v } @@ -347,6 +360,62 @@ export default ({ } } + /** + * Range filter - creates a range query clause + */ + if (itm.filter.type === 'range') { + const rangeQuery: TideSearchRangeFilter = { + time_zone: 'Australia/Melbourne' + } + + if (itm.filter?.format) { + rangeQuery.format = itm.filter.format + } + + if (itm.filter?.value?.start && itm.filter?.value?.end) { + // Match a range against two fields, i.e. start and end dates + const multiRangeQuery = [] + + if (filterVal?.from) { + multiRangeQuery.push({ + range: { + [`${itm.filter?.value?.end}`]: { + gte: filterVal?.from, + ...rangeQuery + } + } + }) + } + + if (filterVal?.to) { + multiRangeQuery.push({ + range: { + [`${itm.filter?.value?.start}`]: { + lte: filterVal?.to, + ...rangeQuery + } + } + }) + } + + return multiRangeQuery + } else { + // Match a range against a single field + if (filterVal?.from) { + rangeQuery.gte = filterVal?.from + } + if (filterVal?.to) { + rangeQuery.lte = filterVal?.to + } + + return { + range: { + [`${itm.filter.value}`]: rangeQuery + } + } + } + } + /** * Dependent queries - create a custom query based off the values of multiple dependent options */ @@ -658,16 +727,19 @@ export default ({ ) // Map the dependent filter object values to be URL friendly - if (filterConfig?.component === 'TideSearchFilterDependent') { - const depValues = Object.fromEntries( + if ( + filterConfig?.component === 'TideSearchFilterDependent' || + filterConfig?.filter?.valueIsObject + ) { + const objValues = Object.fromEntries( // eslint-disable-next-line @typescript-eslint/no-unused-vars Object.entries(value as object).filter(([_key, value]) => Array.isArray(value) ? value.filter(Boolean).length : value ) ) - if (Object.keys(depValues).length) { - value = Object.entries(depValues).map(([key, val]) => { + if (Object.keys(objValues).length) { + value = Object.entries(objValues).map(([key, val]) => { const v = Array.isArray(val) ? val : [val] return `${key}:${v.map(encodeCommasAndColons).join(',')}` }) @@ -752,25 +824,29 @@ export default ({ (filterConfig?.component === 'TideSearchFilterDropdown' && filterConfig?.props?.multiple) || filterConfig?.component === 'TideSearchFilterCheckboxGroup' || - filterConfig?.component === 'TideSearchFilterDependent' + filterConfig?.component === 'TideSearchFilterDependent' || + filterConfig?.filter?.valueIsObject ) { parsedValue = Array.isArray(parsedValue) ? parsedValue : [parsedValue] } // Convert the URL friendly values back into the dependent object - if (filterConfig?.component === 'TideSearchFilterDependent') { + if ( + filterConfig?.component === 'TideSearchFilterDependent' || + filterConfig?.filter?.valueIsObject + ) { parsedValue = Object.fromEntries( - (parsedValue as []).map((dep: string) => { - const [dependentKey, dependentValue] = (dep || '').split(':') + (parsedValue as []).map((v: string) => { + const [objectKey, objectValue] = (v || '').split(':') - const depth = Number(dependentKey.match(/\d+$/)?.[0]) + const depth = Number(objectKey.match(/\d+$/)?.[0]) return [ - dependentKey, + objectKey, filterConfig?.props?.levels?.[depth - 1]?.multiple || filterConfig?.props?.multiple - ? dependentValue.split(',').map(decodeURIComponent) - : decodeURIComponent(dependentValue) + ? objectValue.split(',').map(decodeURIComponent) + : decodeURIComponent(objectValue) ] }) ) @@ -809,7 +885,10 @@ export default ({ */ const resetFilters = (withValues = {}) => { const defaultValues = userFilterConfig.reduce((acc, curr) => { - if (curr.component === 'TideSearchFilterDependent') { + if ( + curr.component === 'TideSearchFilterDependent' || + curr?.filter?.valueIsObject + ) { return { ...acc, [curr.id]: {} } } return { ...acc } diff --git a/packages/ripple-tide-search/types.ts b/packages/ripple-tide-search/types.ts index 1f22882a5e..0729dd62f3 100644 --- a/packages/ripple-tide-search/types.ts +++ b/packages/ripple-tide-search/types.ts @@ -31,8 +31,15 @@ export interface FilterConfigItem { */ component: 'TideSearchFilterDropdown' | string filter?: { - type: 'raw' | 'term' | 'terms' | 'dependent' | 'function' | 'prefix' - value: string + type: + | 'raw' + | 'term' + | 'terms' + | 'dependent' + | 'function' + | 'prefix' + | 'range' + value: string | TideSearchRangeFilterValue /** * Can multiple options be selected? */ @@ -43,6 +50,18 @@ export interface FilterConfigItem { * Only relevant if `searchListingConfig.dynamicAggregations` is true */ excludeFromAggregations?: boolean + /** + * @description used for object based form values, this means an object with multiple properties/values is treated as a single filter in our refine tally + */ + countAsSingle?: boolean + /** + * @description marks a field value as an object, this means it's value won't be a single value or array but an object group + */ + valueIsObject?: boolean + /** + * @description specifies the format the value for the filter query is supplied in (this is used for range queries) + */ + format?: string } aggregations?: { /** @@ -152,10 +171,17 @@ export type TideSearchLocationQueryConfig = { showGeolocationButton?: boolean } -export type TideSearchCustomQueryConfig = { - component?: string - function?: string - props?: Record +export type TideSearchRangeFilter = { + gte?: string + lte?: string + relation?: string + format?: string + time_zone?: string +} + +export type TideSearchRangeFilterValue = { + from: string + to: string } export type TideSearchListingTab = { diff --git a/packages/ripple-tide-search/utils/search.ts b/packages/ripple-tide-search/utils/search.ts index 3391a31cf9..50d72bd234 100644 --- a/packages/ripple-tide-search/utils/search.ts +++ b/packages/ripple-tide-search/utils/search.ts @@ -1,4 +1,5 @@ import { LocationQuery } from 'vue-router' +import type { TideSearchListingConfig } from '../types' /** * @description Helper to get value from elastic search response @@ -68,8 +69,11 @@ export const getActiveFilterURL = (filters) => { /** * @description Helper to calculate the number of applied filters */ -export const getActiveFiltersTally = (values): number => { - return Object.values(values).reduce((acc: number, value): number => { +export const getActiveFiltersTally = ( + values: any, + userFilters: TideSearchListingConfig['userFilters'] = [] +): number => { + return Object.entries(values).reduce((acc: number, [key, value]): number => { if (!value) { return acc } @@ -79,7 +83,14 @@ export const getActiveFiltersTally = (values): number => { } if (typeof value === 'object' && !Array.isArray(value)) { - return acc + getActiveFiltersTally(value) + // Check for objects that should not be counted as a single filter + // i.e. each field in the object group increments our tally + const countAsSingle = userFilters.find((i) => i.id === key)?.filter + ?.countAsSingle + + if (!countAsSingle) { + return acc + getActiveFiltersTally(value) + } } return acc + 1 diff --git a/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.css b/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.css new file mode 100644 index 0000000000..81d25747e5 --- /dev/null +++ b/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.css @@ -0,0 +1,5 @@ +.rpl-form-date-range { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: var(--rpl-sp-3); +} diff --git a/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.stories.mdx b/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.stories.mdx new file mode 100644 index 0000000000..32100a2fb9 --- /dev/null +++ b/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.stories.mdx @@ -0,0 +1,103 @@ +import { + Canvas, + Meta, + Story, + ArgsTable +} from '@storybook/addon-docs' +import RplFormDateRange from './RplFormDateRange.vue' +import StorybookInputFixture from './../StorybookInputFixture/StorybookInputFixture.vue' +import '@dpc-sdp/ripple-ui-core/style/components' +import '../RplForm/RplForm.css' + +export const SingleTemplate = (args) => ({ + components: { RplFormDateRange, StorybookInputFixture }, + setup() { + return { args } + }, + data: () => ({ currentValue: { } }), + methods: { + onChange: function(val) { + this.currentValue = val + } + }, + template: ` + + + +

Output value (not part of component)

{{currentValue}}
+ ` +}) + + + +# Forms + + + + + + {SingleTemplate.bind()} + + + + + + {SingleTemplate.bind()} + + + + + + {SingleTemplate.bind()} + + + + + + {SingleTemplate.bind()} + + + + + + {SingleTemplate.bind()} + + diff --git a/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.vue b/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.vue new file mode 100644 index 0000000000..a353944f01 --- /dev/null +++ b/packages/ripple-ui-forms/src/components/RplFormDateRange/RplFormDateRange.vue @@ -0,0 +1,172 @@ + + + + + + + diff --git a/packages/ripple-ui-forms/src/components/RplFormInput/RplFormInput.vue b/packages/ripple-ui-forms/src/components/RplFormInput/RplFormInput.vue index 0e290ea74a..75d29ca4f3 100644 --- a/packages/ripple-ui-forms/src/components/RplFormInput/RplFormInput.vue +++ b/packages/ripple-ui-forms/src/components/RplFormInput/RplFormInput.vue @@ -21,8 +21,8 @@ interface Props { label?: string prefixIcon?: string suffixIcon?: string - min?: number - max?: number + min?: number | string + max?: number | string minlength?: number maxlength?: number variant?: 'default' | 'reverse' diff --git a/packages/ripple-ui-forms/src/inputs/dateRange.ts b/packages/ripple-ui-forms/src/inputs/dateRange.ts new file mode 100644 index 0000000000..81e66622cb --- /dev/null +++ b/packages/ripple-ui-forms/src/inputs/dateRange.ts @@ -0,0 +1,53 @@ +import { FormKitTypeDefinition } from '@formkit/core' +import { createRplFormGroup, inputLibrary, rplFeatures } from './input-utils' + +/** + * Input definition for a checkbox. + * @public + */ +export const dateRange: FormKitTypeDefinition = { + /** + * The actual schema of the input, or a function that returns the schema. + */ + schema: createRplFormGroup({ + $cmp: 'RplFormDateRange', + props: { + id: `$id`, + name: '$node.name', + label: '$label', + value: '$_value', + onChange: '$node.input', + min: '$node.props.min', + max: '$node.props.max', + dateFormat: '$node.props.dateFormat', + disabled: '$node.context.disabled', + invalid: '$fns.isFieldInvalid()', + required: '$fns.isFieldRequired()', + variant: '$node.props.variant', + pii: '$node.props.pii', + 'aria-describedby': '$fns.getAriaDescribedBy()' + } + }), + library: inputLibrary, + /** + * The type of node, can be a list, group, or input. + */ + type: 'input', + /** + * The family of inputs this one belongs too. For example "text" and "email" + * are both part of the "text" family. This is primary used for styling. + */ + family: 'box', + /** + * An array of extra props to accept for this input. + */ + props: ['min', 'max', 'dateFormat', 'variant', 'pii'], + /** + * Forces node.props.type to be this explicit value. + */ + forceTypeProp: 'date', + /** + * Additional features that should be added to your input + */ + features: rplFeatures +} diff --git a/packages/ripple-ui-forms/src/inputs/index.ts b/packages/ripple-ui-forms/src/inputs/index.ts index de01bd26a9..bb46e30d30 100644 --- a/packages/ripple-ui-forms/src/inputs/index.ts +++ b/packages/ripple-ui-forms/src/inputs/index.ts @@ -11,6 +11,7 @@ export { radioGroup } from './radioGroup' export { optionButtons } from './optionButtons' export { dropdown } from './dropdown' export { datePicker } from './datePicker' +export { dateRange } from './dateRange' export { content } from './content' export { label } from './label' export { fieldset } from './fieldset' diff --git a/packages/ripple-ui-forms/src/inputs/input-utils.ts b/packages/ripple-ui-forms/src/inputs/input-utils.ts index b542d7fc2d..661adbfd76 100644 --- a/packages/ripple-ui-forms/src/inputs/input-utils.ts +++ b/packages/ripple-ui-forms/src/inputs/input-utils.ts @@ -31,6 +31,7 @@ import RplFormRadioGroup from './../components/RplFormOptions/RplFormRadioGroup. import RplFormOptionButtons from './../components/RplFormOptionButtons/RplFormOptionButtons.vue' import RplFormDropdown from './../components/RplFormDropdown/RplFormDropdown.vue' import RplFormDate from './../components/RplFormDate/RplFormDate.vue' +import RplFormDateRange from './../components/RplFormDateRange/RplFormDateRange.vue' import RplFormValidationError from './../components/RplFormValidationError/RplFormValidationError.vue' import RplFormHelpText from './../components/RplFormHelpText/RplFormHelpText.vue' import RplFormLabel from './../components/RplFormLabel/RplFormLabel.vue' @@ -53,6 +54,7 @@ export const inputLibrary = { RplFormOptionButtons: markRaw(RplFormOptionButtons), RplFormDropdown: markRaw(RplFormDropdown), RplFormDate: markRaw(RplFormDate), + RplFormDateRange: markRaw(RplFormDateRange), RplFormValidationError: markRaw(RplFormValidationError), RplFormHelpText: markRaw(RplFormHelpText), RplFormLabel: markRaw(RplFormLabel), diff --git a/packages/ripple-ui-forms/src/plugin.ts b/packages/ripple-ui-forms/src/plugin.ts index e490763253..6da19bcf48 100644 --- a/packages/ripple-ui-forms/src/plugin.ts +++ b/packages/ripple-ui-forms/src/plugin.ts @@ -15,6 +15,7 @@ import { divider, date, datePicker, + dateRange, optionButtons, fieldset, hidden @@ -52,6 +53,8 @@ rplFormInputs.library = (node) => { return node.define(date) case 'RplFormDatePicker': return node.define(datePicker) + case 'RplFormDateRange': + return node.define(dateRange) case 'RplFormContent': return node.define(content) case 'RplFormLabel':