From 9cf6ef4f45b435e9eb298a2b8b421d263912da96 Mon Sep 17 00:00:00 2001
From: Tim Yao <31641325+tim-yao@users.noreply.github.com>
Date: Mon, 14 Oct 2019 09:51:03 +1100
Subject: [PATCH] [SDPA-3306] add mapping example (#555)
* [SDPA-3306] Added example for mapping with minor fix
* Updated search code examples to make them working
---
README.md | 4 +-
examples/basic-examples/README.md | 4 +
.../e2e/integration/custom/mapping.feature | 15 ++
.../custom/mapping/step_definition.js | 15 ++
.../example-override-mapping/README.md | 7 +
.../mapping-filters.js | 40 ++++++
.../example-override-mapping/tide.config.js | 42 ++++++
.../tide/modules/example-search/README.md | 12 +-
.../example-search/components/Search.vue | 125 ++++++++--------
.../components/SearchSimple.vue | 97 +++++++++++++
.../components/formdata-simple.js | 25 ++++
.../example-search/components/formdata.js | 116 +++++++++++++++
.../tide/modules/example-search/formdata.js | 135 ------------------
.../tide/modules/example-search/module.js | 5 +
examples/basic-examples/tide/tide.config.js | 1 +
.../test/e2e/integration/smoke/ripple.feature | 4 +-
packages/ripple-nuxt-tide/lib/core/mapping.js | 7 +-
17 files changed, 448 insertions(+), 206 deletions(-)
create mode 100644 examples/basic-examples/test/e2e/integration/custom/mapping.feature
create mode 100644 examples/basic-examples/test/e2e/integration/custom/mapping/step_definition.js
create mode 100644 examples/basic-examples/tide/modules/example-override-mapping/README.md
create mode 100644 examples/basic-examples/tide/modules/example-override-mapping/mapping-filters.js
create mode 100644 examples/basic-examples/tide/modules/example-override-mapping/tide.config.js
create mode 100644 examples/basic-examples/tide/modules/example-search/components/SearchSimple.vue
create mode 100644 examples/basic-examples/tide/modules/example-search/components/formdata-simple.js
create mode 100644 examples/basic-examples/tide/modules/example-search/components/formdata.js
delete mode 100644 examples/basic-examples/tide/modules/example-search/formdata.js
diff --git a/README.md b/README.md
index 6de91526c..046480ce2 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@
* [Built With](#built-with)
* [Usage](#usage)
* [In a Nuxt application](#in-a-Nuxt-application)
- * [In a Vue project](#in-a-vue-project)
+ * [In a Vue project](#in-a-vuejs-projectnot-nuxtjs)
* [Contributing](#contributing)
* [Getting Started](#getting-started)
* [Requirements](#requirements)
@@ -114,7 +114,7 @@ You can optionally pass options to `@dpc-sdp/ripple-nuxt-ui` by adding the `ripp
Ripple components are published individually as npm modules and can be imported in any Vue project.
-Check out our [Vue app example](https://github.com/dpc-sdp/ripple/tree/develop/examples/basic-examples).
+Check out our [Vue app example](https://github.com/dpc-sdp/ripple/tree/develop/examples/vue-example-app).
## Contributing
diff --git a/examples/basic-examples/README.md b/examples/basic-examples/README.md
index e2f5b29d2..158d9348d 100644
--- a/examples/basic-examples/README.md
+++ b/examples/basic-examples/README.md
@@ -28,6 +28,10 @@
Provide a example for overriding the Ripple components in Tide landing page which
is dynamically loaded.
+- [Override component mapping](tide/modules/example-override-mapping/)
+
+ Provide a example for overriding the components mapping.
+
- [Custom search page](tide/modules/example-search/)
Provide a example for adding a custom search page.
diff --git a/examples/basic-examples/test/e2e/integration/custom/mapping.feature b/examples/basic-examples/test/e2e/integration/custom/mapping.feature
new file mode 100644
index 000000000..ecac71bc3
--- /dev/null
+++ b/examples/basic-examples/test/e2e/integration/custom/mapping.feature
@@ -0,0 +1,15 @@
+Feature: Custom mapping
+
+ Custom mapping should work
+
+ Background:
+ Given I visit the page "/"
+
+ Scenario: Example for overriding mapping with custom filter
+ And the example filter is applied
+
+ Scenario: Example for adding async filter
+ And the example async filter is applied
+
+ Scenario: Example for overriding core filter
+ And the core filter is overrode
diff --git a/examples/basic-examples/test/e2e/integration/custom/mapping/step_definition.js b/examples/basic-examples/test/e2e/integration/custom/mapping/step_definition.js
new file mode 100644
index 000000000..e43262db0
--- /dev/null
+++ b/examples/basic-examples/test/e2e/integration/custom/mapping/step_definition.js
@@ -0,0 +1,15 @@
+/* global cy */
+
+import { Then } from 'cypress-cucumber-preprocessor/steps'
+
+Then(`the example filter is applied`, () => {
+ cy.get('.rpl-hero-banner__title span').should('contain', '[demo]')
+})
+
+Then(`the example async filter is applied`, () => {
+ cy.get('.rpl-hero-banner__description').should('contain', '[demo]')
+})
+
+Then(`the core filter is overrode`, () => {
+ cy.get('.rpl-hero-banner__link-list-item .rpl-text-label span span').should('contain', '[demo]')
+})
diff --git a/examples/basic-examples/tide/modules/example-override-mapping/README.md b/examples/basic-examples/tide/modules/example-override-mapping/README.md
new file mode 100644
index 000000000..5f3c01990
--- /dev/null
+++ b/examples/basic-examples/tide/modules/example-override-mapping/README.md
@@ -0,0 +1,7 @@
+# Ripple with custom mapping example
+
+The mapping config is for mapping Tide data to Frontend Vue component(Not have to be Ripple components).
+
+This is a example for overriding the Ripple default component mapping.
+
+In this module, we are override the `heroBanner` mapping with custom filters.
diff --git a/examples/basic-examples/tide/modules/example-override-mapping/mapping-filters.js b/examples/basic-examples/tide/modules/example-override-mapping/mapping-filters.js
new file mode 100644
index 000000000..19a165e91
--- /dev/null
+++ b/examples/basic-examples/tide/modules/example-override-mapping/mapping-filters.js
@@ -0,0 +1,40 @@
+// Filters for adding extra process on a mapping value
+
+// Create more filters if need.
+module.exports = {
+
+ // Add your own filter, must with your own name prefix to avoid name conflict.
+ eomPageTitle: (pageTitle) => {
+ return `[demo] ${pageTitle}`
+ },
+
+ // An async filter example.
+ eomIntroText: async (introText) => {
+ const promise = new Promise((resolve, reject) => {
+ // Do some process
+ setTimeout(function () {
+ const processed = `[demo] ${introText}`
+ resolve(processed)
+ }, 300)
+ })
+ return promise
+ },
+
+ // We can override core filter by using same core filter name.
+ // Ripple v1.3.x required for this feature.
+ // ! Be careful, this way is hard to maintain.
+ // Use your own filter like above is the safer way.
+ paragraphKeyJourneyLinks: function (fieldParagraphLinks) {
+ if (typeof fieldParagraphLinks !== 'undefined' && fieldParagraphLinks !== null) {
+ let rtn = []
+ fieldParagraphLinks.forEach(item => {
+ rtn.push({
+ url: item.url || item.uri,
+ text: `[demo] ${item.title}`
+ })
+ })
+ return rtn
+ }
+ }
+
+}
diff --git a/examples/basic-examples/tide/modules/example-override-mapping/tide.config.js b/examples/basic-examples/tide/modules/example-override-mapping/tide.config.js
new file mode 100644
index 000000000..0989cd9cf
--- /dev/null
+++ b/examples/basic-examples/tide/modules/example-override-mapping/tide.config.js
@@ -0,0 +1,42 @@
+// Grid columns setting for cards.
+
+module.exports = {
+
+ mapping: {
+ tideField: {
+
+ // A example for overriding default `heroBanner` mapping in https://github.com/dpc-sdp/ripple/blob/v1.2.1/packages/ripple-nuxt-tide/lib/config/tide.config.js#L33
+ // You can do:
+ // - Map to your own component.
+ // - Use your own filters to process the Tide field data.
+ 'heroBanner': {
+ component: 'rpl-hero-banner',
+ props: {
+ title: {
+ field: 'pageTitle',
+ // Demo of a custom filter here.
+ filters: ['eomPageTitle']
+ },
+ introText: {
+ field: 'introText',
+ // Demo of another custom filter here.
+ filters: ['eomIntroText']
+ },
+ linkHeading: ['keyJourneys', 'field_paragraph_title'],
+ links: {
+ field: ['keyJourneys', 'field_paragraph_links'],
+ filters: ['paragraphKeyJourneyLinks']
+ },
+ moreLink: {
+ field: ['keyJourneys', 'field_paragraph_cta'],
+ filters: ['paragraphCta']
+ },
+ theme: 'theme',
+ showLinks: 'showLinks',
+ logo: 'logo',
+ backgroundGraphic: 'backgroundGraphic'
+ }
+ }
+ }
+ }
+}
diff --git a/examples/basic-examples/tide/modules/example-search/README.md b/examples/basic-examples/tide/modules/example-search/README.md
index 0f392c431..7d899a7a1 100644
--- a/examples/basic-examples/tide/modules/example-search/README.md
+++ b/examples/basic-examples/tide/modules/example-search/README.md
@@ -4,6 +4,14 @@ This example shows how to add a custom search page.
Three files required:
-- `Search.vue`: Used for providing search form and search results.
-- `formdata.js`: Used for providing search form configuration.
+- Vue component e.g `Search.vue`: Used for providing search form and search results.
+- Form config e.g `formdata.js`: Used for providing search form configuration.
- `module.js`: Used for providing search page route.
+
+## Example search simple
+
+It adds a very basic search page `/example-search-simple` has basic elements only.
+
+## Example search
+
+It adds a search page `/example-search`.
diff --git a/examples/basic-examples/tide/modules/example-search/components/Search.vue b/examples/basic-examples/tide/modules/example-search/components/Search.vue
index 549521e06..4881fdbf6 100644
--- a/examples/basic-examples/tide/modules/example-search/components/Search.vue
+++ b/examples/basic-examples/tide/modules/example-search/components/Search.vue
@@ -1,50 +1,45 @@
-
-
-
-
-
-
-
+
+
-
-
diff --git a/examples/basic-examples/tide/modules/example-search/components/SearchSimple.vue b/examples/basic-examples/tide/modules/example-search/components/SearchSimple.vue
new file mode 100644
index 000000000..506beb5cc
--- /dev/null
+++ b/examples/basic-examples/tide/modules/example-search/components/SearchSimple.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/basic-examples/tide/modules/example-search/components/formdata-simple.js b/examples/basic-examples/tide/modules/example-search/components/formdata-simple.js
new file mode 100644
index 000000000..17a044cf9
--- /dev/null
+++ b/examples/basic-examples/tide/modules/example-search/components/formdata-simple.js
@@ -0,0 +1,25 @@
+export default {
+ getFormData: async setFilterOptions => {
+ return {
+ title: 'Example search simple',
+ subtitle: 'A simple search form, no filters, default results style. Search "event".',
+ searchPlaceholder: 'Start typing...',
+ theme: 'light',
+ expandFilters: true,
+ allowBlank: true,
+ filterForm: {
+ tideId: 'tide_search_form',
+ tag: 'rpl-fieldset',
+ model: {
+ },
+ schema: {
+ },
+ formOptions: {
+ validateAfterLoad: false,
+ validateAfterChanged: false
+ },
+ formState: {}
+ }
+ }
+ }
+}
diff --git a/examples/basic-examples/tide/modules/example-search/components/formdata.js b/examples/basic-examples/tide/modules/example-search/components/formdata.js
new file mode 100644
index 000000000..d19d97d72
--- /dev/null
+++ b/examples/basic-examples/tide/modules/example-search/components/formdata.js
@@ -0,0 +1,116 @@
+export default {
+ getFormData: async setFilterOptions => {
+ const eventCategoryValues = await setFilterOptions({
+ fieldName: 'field_event_category_name'
+ })
+ const eventNameValues = await setFilterOptions({
+ fieldName: 'field_event_details_event_requirements_name'
+ })
+ return {
+ title: 'Example search page',
+ subtitle: 'A search form with filters, card result style. Search "event".',
+ searchPlaceholder: 'Start typing...',
+ theme: 'light',
+ allowBlank: true,
+ filterForm: {
+ tideId: 'tide_search_form',
+ tag: 'rpl-fieldset',
+ model: {
+ // Multi-value fields should always be an array.
+ field_event_category_name: [],
+ field_event_date_end_value: '',
+ location: '',
+ field_event_details_event_requirements_name: []
+ },
+ schema: {
+ groups: [
+ {
+ fields: [
+ {
+ type: 'rplchecklist',
+ styleClasses: ['form-group--col-two'],
+ label: 'Select an event category',
+ model: 'field_event_category_name',
+ values: eventCategoryValues,
+ placeholder: 'Select a topic',
+ // TODO: Update 'filter' key to 'query' to make purpose clearer.
+ filter: {
+ type: 'term',
+ operator: ''
+ }
+ },
+ {
+ type: 'input',
+ inputType: 'text',
+ maxlength: 50,
+ styleClasses: ['form-group--col-two'],
+ label: 'Location',
+ model: 'location',
+ placeholder: 'Start typing suburb or postcode...',
+ filter: {
+ type: 'multiMatch',
+ operator: '',
+ fields: [
+ 'field_event_details_event_locality',
+ 'field_event_details_event_postal_code'
+ ]
+ }
+ }
+ ]
+ },
+ {
+ fields: [
+ {
+ type: 'rpldatepicker',
+ ranged: false,
+ styleClasses: ['form-group--col-two'],
+ label: 'Select an event date',
+ model: 'field_event_date_end_value',
+ placeholder: 'DD/MM/YYYY',
+ filter: {
+ type: 'date',
+ operator: 'gte'
+ }
+ },
+ {
+ type: 'rplchecklist',
+ label: 'Event requirements',
+ styleClasses: ['form-group--col-two'],
+ model: 'field_event_details_event_requirements_name',
+ // TODO: There are no values for this field how can we programmactically hide a field in this instance.
+ values: eventNameValues,
+ placeholder: 'Please select',
+ filter: {
+ type: 'term',
+ operator: ''
+ }
+ }
+ ]
+ },
+ {
+ fields: [
+ {
+ type: 'rplsubmitloader',
+ buttonText: 'Apply change',
+ loading: false,
+ autoUpdate: true,
+ styleClasses: ['form-group--inline']
+ },
+ {
+ type: 'rplclearform',
+ buttonText: 'Clear search filters',
+ styleClasses: ['form-group--inline']
+ }
+ ]
+ }
+ ]
+ },
+ formOptions: {
+ validateAfterLoad: false,
+ validateAfterChanged: false
+ },
+ formState: {}
+ }
+ }
+ }
+}
diff --git a/examples/basic-examples/tide/modules/example-search/formdata.js b/examples/basic-examples/tide/modules/example-search/formdata.js
deleted file mode 100644
index 405bb4770..000000000
--- a/examples/basic-examples/tide/modules/example-search/formdata.js
+++ /dev/null
@@ -1,135 +0,0 @@
-export default {
- getFormData: async setFilterOptions => {
- const fieldProfileCategoryValues = await setFilterOptions({
- fieldName: 'field_profile_category_name'
- })
- const fieldYearValues = await setFilterOptions({
- fieldName: 'field_year'
- })
- const fieldProfileExpertiseNameValues = await setFilterOptions({
- fieldName: 'field_profile_expertise_name'
- })
- const fieldLocationNameValues = await setFilterOptions({
- fieldName: 'field_location_name'
- })
-
- return {
- title: 'Victorian Honour Roll of women inductees',
- subtitle: 'View our outstanding inductees.',
- searchPlaceholder: 'Start typing...',
- theme: 'light',
- textSearch: false,
- expandFilters: true,
- allowBlank: true,
- filterForm: {
- tag: 'rpl-fieldset',
- tideId: 'tide_search_form',
- model: {
- title: '',
- field_profile_category_name: [],
- field_year: [],
- field_profile_expertise_name: [],
- field_location_name: []
- },
- schema: {
- groups: [
- {
- legend: 'View by',
- fields: [
- {
- type: 'input',
- inputType: 'text',
- maxlength: 50,
- styleClasses: ['form-group--col-two'],
- label: 'Honouree name',
- model: 'title',
- placeholder: 'Start typing first name or surname...',
- filter: {
- type: 'term'
- }
- },
- {
- type: 'rplchecklist',
- label: 'Category',
- model: 'field_profile_category_name',
- styleClasses: ['form-group--col-two'],
- values: fieldProfileCategoryValues,
- placeholder: 'Select a category',
- filter: {
- type: 'term',
- operator: ''
- }
- }
- ]
- },
- {
- fields: [
- {
- type: 'rplchecklist',
- label: 'Induction year',
- model: 'field_year',
- styleClasses: ['form-group--col-two'],
- values: fieldYearValues.filter(year => year.length === 4), // TODO: Temporary fix for invalid response in search index [SDPA-2000]
- placeholder: 'Select a year',
- filter: {
- type: 'term',
- operator: ''
- }
- },
- {
- type: 'rplchecklist',
- label: 'Field of expertise',
- model: 'field_profile_expertise_name',
- styleClasses: ['form-group--col-two'],
- values: fieldProfileExpertiseNameValues,
- placeholder: 'Select field of expertise',
- filter: {
- type: 'term',
- operator: ''
- }
- }
- ]
- },
- {
- fields: [
- {
- type: 'rplchecklist',
- label: 'Location',
- model: 'field_location_name',
- styleClasses: ['form-group--col-two'],
- values: fieldLocationNameValues,
- placeholder: 'Select a location',
- filter: {
- type: 'term',
- operator: ''
- }
- }
- ]
- },
- {
- fields: [
- {
- type: 'rplsubmitloader',
- buttonText: 'Apply change',
- loading: false,
- autoUpdate: true,
- styleClasses: ['form-group--inline']
- },
- {
- type: 'rplclearform',
- buttonText: 'Clear search filters',
- styleClasses: ['form-group--inline']
- }
- ]
- }
- ]
- },
- formOptions: {
- validateAfterLoad: false,
- validateAfterChanged: false
- },
- formState: {}
- }
- }
- }
-}
diff --git a/examples/basic-examples/tide/modules/example-search/module.js b/examples/basic-examples/tide/modules/example-search/module.js
index 05ace4fc5..763967793 100644
--- a/examples/basic-examples/tide/modules/example-search/module.js
+++ b/examples/basic-examples/tide/modules/example-search/module.js
@@ -6,5 +6,10 @@ module.exports = function () {
path: '/example-search',
component: '~/tide/modules/example-search/components/Search.vue'
})
+ routes.push({
+ name: 'example-search-simple',
+ path: '/example-search-simple',
+ component: '~/tide/modules/example-search/components/SearchSimple.vue'
+ })
})
}
diff --git a/examples/basic-examples/tide/tide.config.js b/examples/basic-examples/tide/tide.config.js
index 97148823d..9ec71713b 100644
--- a/examples/basic-examples/tide/tide.config.js
+++ b/examples/basic-examples/tide/tide.config.js
@@ -6,6 +6,7 @@ const tideConfig = {
'example-middleware',
'example-content-type',
'example-override-component',
+ 'example-override-mapping',
'example-search'
]
}
diff --git a/examples/vue-example-app/test/e2e/integration/smoke/ripple.feature b/examples/vue-example-app/test/e2e/integration/smoke/ripple.feature
index 226f102e0..4b33cfb92 100644
--- a/examples/vue-example-app/test/e2e/integration/smoke/ripple.feature
+++ b/examples/vue-example-app/test/e2e/integration/smoke/ripple.feature
@@ -1,6 +1,6 @@
-Feature: Custom theme should work
+Feature: Ripple components
- Custom theme is getting loaded
+ Ripple components in Vue.js app
Background:
Given I visit the Vue router path "/"
diff --git a/packages/ripple-nuxt-tide/lib/core/mapping.js b/packages/ripple-nuxt-tide/lib/core/mapping.js
index 5c3f9273c..003daa66f 100644
--- a/packages/ripple-nuxt-tide/lib/core/mapping.js
+++ b/packages/ripple-nuxt-tide/lib/core/mapping.js
@@ -1,5 +1,6 @@
import tideDefaultConfig from '../config/tide.config'
import defaultFilters from './mapping-filters'
+import logger from './logger'
const _getValFromFieldArray = Symbol('getValFromFieldArray')
const _getValFromFieldOptions = Symbol('getValFromFieldOptions')
@@ -90,9 +91,11 @@ export class Mapping {
if (configForMergeIn) {
for (const type in configForMergeIn) {
if (config[type] && typeof configForMergeIn[type] !== 'function') {
- // We don't allow function in core to be overriden in extend or custom config.
config[type] = Object.assign(config[type], configForMergeIn[type])
- } else if (config[type] === undefined && typeof configForMergeIn[type] === 'function') {
+ } else if (typeof configForMergeIn[type] === 'function') {
+ if (config[type] && process.server) {
+ logger.info('Mapping filter "%s" has been overridden by custom module', type, { label: 'Mapping' })
+ }
config[type] = configForMergeIn[type]
} else {
config[type] = Object.assign({}, configForMergeIn[type])