From 3f111f98fdf0a4175dce0a5d8711bb8d4e4729df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20CG?= Date: Mon, 8 Jul 2024 10:59:28 +0200 Subject: [PATCH 1/3] feat(renderless-extra-param): migrate to composition API (#1546) --- .../test-renderless-extra-param.vue | 16 ++++ .../src/components/index.ts | 1 + packages/_vue3-migration-test/src/router.ts | 8 +- .../__tests__/renderless-extra-params.spec.ts | 2 +- .../components/renderless-extra-param.vue | 86 +++++++++---------- 5 files changed, 68 insertions(+), 45 deletions(-) create mode 100644 packages/_vue3-migration-test/src/components/extra-params/test-renderless-extra-param.vue diff --git a/packages/_vue3-migration-test/src/components/extra-params/test-renderless-extra-param.vue b/packages/_vue3-migration-test/src/components/extra-params/test-renderless-extra-param.vue new file mode 100644 index 0000000000..5d543a55bf --- /dev/null +++ b/packages/_vue3-migration-test/src/components/extra-params/test-renderless-extra-param.vue @@ -0,0 +1,16 @@ + + diff --git a/packages/_vue3-migration-test/src/components/index.ts b/packages/_vue3-migration-test/src/components/index.ts index c845db065a..6fff4ac5e2 100644 --- a/packages/_vue3-migration-test/src/components/index.ts +++ b/packages/_vue3-migration-test/src/components/index.ts @@ -17,3 +17,4 @@ export { default as TestBaseIdModal } from './modals/test-base-id-modal.vue'; export { default as TestExtraParams } from './extra-params/test-extra-params.vue'; export { default as TestSearch } from './test-search.vue'; export { default as TestTagging } from './tagging/test-tagging.vue'; +export { default as TestRenderlessExtraParam } from './extra-params/test-renderless-extra-param.vue'; diff --git a/packages/_vue3-migration-test/src/router.ts b/packages/_vue3-migration-test/src/router.ts index ce24a8afac..3fa3d23554 100644 --- a/packages/_vue3-migration-test/src/router.ts +++ b/packages/_vue3-migration-test/src/router.ts @@ -45,7 +45,8 @@ import { TestRedirection, TestExtraParams, TestSearch, - TestTagging + TestTagging, + TestRenderlessExtraParam } from './'; const routes = [ @@ -278,6 +279,11 @@ const routes = [ path: '/tagging', name: 'Tagging', component: TestTagging + }, + { + path: '/renderless-extra-param', + name: 'RenderlessExtraParam', + component: TestRenderlessExtraParam } ]; diff --git a/packages/x-components/src/x-modules/extra-params/components/__tests__/renderless-extra-params.spec.ts b/packages/x-components/src/x-modules/extra-params/components/__tests__/renderless-extra-params.spec.ts index ea30325d82..0f97794e65 100644 --- a/packages/x-components/src/x-modules/extra-params/components/__tests__/renderless-extra-params.spec.ts +++ b/packages/x-components/src/x-modules/extra-params/components/__tests__/renderless-extra-params.spec.ts @@ -82,7 +82,7 @@ describe('testing RenderlessExtraParam component', () => { expect(userChangedExtraParamsCallback).toHaveBeenCalledWith<[WirePayload>]>( { eventPayload: { warehouse: 45678 }, - metadata: { moduleName: 'extraParams', location: undefined, replaceable: true } + metadata: { moduleName: 'extraParams', location: 'none', replaceable: true } } ); diff --git a/packages/x-components/src/x-modules/extra-params/components/renderless-extra-param.vue b/packages/x-components/src/x-modules/extra-params/components/renderless-extra-param.vue index 05b32ff030..c7258312d9 100644 --- a/packages/x-components/src/x-modules/extra-params/components/renderless-extra-param.vue +++ b/packages/x-components/src/x-modules/extra-params/components/renderless-extra-param.vue @@ -5,11 +5,10 @@ From 5d8b0b462cf5304d06fd8aafd7d3cc23bf23317d Mon Sep 17 00:00:00 2001 From: empathy/x Date: Mon, 8 Jul 2024 09:14:26 +0000 Subject: [PATCH 2/3] chore(release): publish - vue3-migration-test@1.0.0-alpha.42 - @empathyco/x-components@5.0.0-alpha.62 --- packages/_vue3-migration-test/CHANGELOG.md | 9 +++++++++ packages/_vue3-migration-test/package.json | 2 +- packages/x-components/CHANGELOG.md | 9 +++++++++ packages/x-components/package.json | 2 +- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/_vue3-migration-test/CHANGELOG.md b/packages/_vue3-migration-test/CHANGELOG.md index 205a5256b9..40f1070722 100644 --- a/packages/_vue3-migration-test/CHANGELOG.md +++ b/packages/_vue3-migration-test/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.0.0-alpha.42](https://github.com/empathyco/x/compare/vue3-migration-test@1.0.0-alpha.41...vue3-migration-test@1.0.0-alpha.42) (2024-07-08) + + +### Features + +* **renderless-extra-param:** migrate to composition API (#1546) ([3f111f9](https://github.com/empathyco/x/commit/3f111f98fdf0a4175dce0a5d8711bb8d4e4729df)) + + + ## [1.0.0-alpha.41](https://github.com/empathyco/x/compare/vue3-migration-test@1.0.0-alpha.40...vue3-migration-test@1.0.0-alpha.41) (2024-07-03) diff --git a/packages/_vue3-migration-test/package.json b/packages/_vue3-migration-test/package.json index d4c75efcdd..a331aa113a 100644 --- a/packages/_vue3-migration-test/package.json +++ b/packages/_vue3-migration-test/package.json @@ -1,7 +1,7 @@ { "name": "vue3-migration-test", "private": "true", - "version": "1.0.0-alpha.41", + "version": "1.0.0-alpha.42", "scripts": { "dev": "vite", "preview": "vite preview", diff --git a/packages/x-components/CHANGELOG.md b/packages/x-components/CHANGELOG.md index 3af4323854..2fe8bc90aa 100644 --- a/packages/x-components/CHANGELOG.md +++ b/packages/x-components/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-alpha.62](https://github.com/empathyco/x/compare/@empathyco/x-components@5.0.0-alpha.61...@empathyco/x-components@5.0.0-alpha.62) (2024-07-08) + + +### Features + +* **renderless-extra-param:** migrate to composition API (#1546) ([3f111f9](https://github.com/empathyco/x/commit/3f111f98fdf0a4175dce0a5d8711bb8d4e4729df)) + + + ## [5.0.0-alpha.61](https://github.com/empathyco/x/compare/@empathyco/x-components@5.0.0-alpha.60...@empathyco/x-components@5.0.0-alpha.61) (2024-07-03) diff --git a/packages/x-components/package.json b/packages/x-components/package.json index 8a48205d1f..e76c47fccf 100644 --- a/packages/x-components/package.json +++ b/packages/x-components/package.json @@ -1,6 +1,6 @@ { "name": "@empathyco/x-components", - "version": "5.0.0-alpha.61", + "version": "5.0.0-alpha.62", "description": "Empathy X Components", "author": "Empathy Systems Corporation S.L.", "license": "Apache-2.0", From dd6a2d728632e81c25cc918c1cac1aa10daab590 Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:30:21 +0200 Subject: [PATCH 3/3] feat: migrate filters components to Composition API (#1550) --- .../facets/components/test-filters.vue | 99 +++- .../editable-number-range-filter.spec.ts | 9 +- .../filters/editable-number-range-filter.vue | 441 +++++++++--------- .../filters/hierarchical-filter.vue | 220 ++++----- .../filters/number-range-filter.vue | 95 ++-- 5 files changed, 490 insertions(+), 374 deletions(-) diff --git a/packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue b/packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue index 162e93bd81..015f9cf840 100644 --- a/packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue +++ b/packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue @@ -28,12 +28,69 @@ +
+
+
+

Number Range Filter

+ +
+
+
+

Editable Number Range Filter

+ + + + + + +
⚠️ Invalid range values
+
+
+
+
+

Hierarchical Filter

+ + + - diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/editable-number-range-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/editable-number-range-filter.spec.ts index 24cf08addf..fc7b7bda50 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/editable-number-range-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/editable-number-range-filter.spec.ts @@ -1,7 +1,7 @@ import { EditableNumberRangeFilter, RangeValue } from '@empathyco/x-types'; import { DeepPartial } from '@empathyco/x-utils'; import { createLocalVue, mount, Wrapper } from '@vue/test-utils'; -import Vue from 'vue'; +import Vue, { Ref, ref } from 'vue'; import Vuex, { Store } from 'vuex'; // eslint-disable-next-line max-len import { createEditableNumberRangeFilter } from '../../../../../__stubs__/filters-stubs.factory'; @@ -34,13 +34,12 @@ function renderEditableNumberRangeFilter({ /> `, range, - filter = createEditableNumberRangeFilter('age', range), + filter = ref(createEditableNumberRangeFilter('age', range)), isInstant = false, hasClearButton = true, buttonsClass, inputsClass }: EditableNumberRangeFilterOptions = {}): EditableNumberRangeFilterAPI { - Vue.observable(filter); const localVue = createLocalVue(); localVue.use(Vuex); const store = new Store>({}); @@ -343,7 +342,7 @@ interface EditableNumberRangeFilterOptions { * The {@link @empathyco/x-types#EditableNumberRangeFilter | EditableNumberRangeFilter} object * to be passed to the component. */ - filter?: EditableNumberRangeFilter; + filter?: Ref; /** `hasClearButton` property to init the component. */ hasClearButton?: boolean; /** `isInstant` property to init the component. */ @@ -364,7 +363,7 @@ interface EditableNumberRangeFilterAPI { /** Clear button wrapper. */ clearButtonWrapper: Wrapper; /** The filter passed to the component. */ - filter: EditableNumberRangeFilter; + filter: Ref; /** Filter component wrapper. */ filterWrapper: Wrapper; /** Max input element wrapper. */ diff --git a/packages/x-components/src/x-modules/facets/components/filters/editable-number-range-filter.vue b/packages/x-components/src/x-modules/facets/components/filters/editable-number-range-filter.vue index 7b8f338c1e..4d7772eb91 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/editable-number-range-filter.vue +++ b/packages/x-components/src/x-modules/facets/components/filters/editable-number-range-filter.vue @@ -86,12 +86,9 @@ EditableNumberRangeFilter as EditableNumberRangeFilterModel, RangeValue } from '@empathyco/x-types'; - import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; - import { VueCSSClasses } from '../../../../utils/types'; + import { defineComponent, PropType, watch, ref, Ref, computed } from 'vue'; import { facetsXModule } from '../../x-module'; - import { xComponentMixin } from '../../../../components/x-component.mixin'; - import { XOn } from '../../../../components'; - import { dynamicPropsMixin } from '../../../../components/dynamic-props.mixin'; + import { use$x } from '../../../../composables'; /** * Renders an editable number range filter. It has two input fields to handle min and max values, @@ -108,219 +105,239 @@ * * @public */ - @Component({ - mixins: [xComponentMixin(facetsXModule), dynamicPropsMixin(['inputsClass', 'buttonsClass'])] - }) - export default class EditableNumberRangeFilter extends Vue { - /** - * Component min value. - * - * @internal - */ - protected min: RangeValue['min'] = null; - /** - * Component max value. - * - * @internal - */ - protected max: RangeValue['max'] = null; - - /** - * The filter data to render and edit. - * - * @public - */ - @Prop({ required: true }) - public filter!: EditableNumberRangeFilterModel; - - /** - * If `instant` prop is true, the needed events are emitted immediately; else, apply button is - * rendered to confirm to do it. False by default. - * - * @public - */ - @Prop({ default: false }) - public isInstant!: boolean; - - /** - * If `clear` prop is true, clear button, which sets to null component min and max values, is - * rendered. True by default. - * - * @public - */ - @Prop({ default: true }) - public hasClearButton!: boolean; - - /** - * It watches the filter range values passed as property and updates component range values if - * they change. - * - * @param newRange - New range value. - * - * @internal - */ - @Watch('filter.range', { immediate: true, deep: true }) - onFilterChanged(newRange: RangeValue): void { - this.min = newRange.min; - this.max = newRange.max; - } - - /** - * It watches range values in order to emit the event with the change if `isInstant` - * property is true. - * - * @internal - */ - @Watch('range', { deep: true }) - protected instantEmitUserModifiedFilter(): void { - if (this.isInstant) { - this.emitUserModifiedFilter(); - } - } - - /** - * It resets the min/max range values to null if the - * {@link FacetsXEvents.UserClickedClearAllFilters} event is fired. - * - * @public - */ - @XOn('UserClickedClearAllFilters') - resetRanges(): void { - this.clearValues(); - } - - /** - * Dynamic CSS classes. - * - * @returns Object which contains dynamic CSS classes. - * - * @internal - */ - protected get cssClasses(): VueCSSClasses { - return { 'x-editable-number-range-filter--error': this.hasError }; - } - - /** - * Returns {@link @empathyco/x-types#RangeValue} with component min and max - * values. - * - * @returns Range value object with component values. - * - * @internal - */ - protected get range(): RangeValue { - return { min: this.min, max: this.max }; - } - - /** - * It returns true if the property `hasClearButton` is true and there are values to clear. - * - * @returns True if the clear button has to be rendered. - * - * @internal - */ - protected get renderClearButton(): boolean { - return this.hasClearButton && !this.isAnyRange; - } - - /** - * It checks if component min and max values are valid. - * - * @returns True if there is any error in the component min and max values. - * - * @internal - */ - protected get hasError(): boolean { - return this.min !== null && this.max !== null && this.min > this.max; - } - - /** - * It checks if component min and max values are different from the ones within the filter - * provided as property. - * - * @returns True if they are different. - * - * @internal - */ - protected get areValuesDifferent(): boolean { - return this.min !== this.filter.range.min || this.max !== this.filter.range.max; - } - - /** - * Checks if the range of the filter allows any value, which happens when the min is - * null or 0 and the max is null. - * - * @returns True if the range of the filter allows any value. - * - * @internal - */ - protected get isAnyRange(): boolean { - return !this.min && this.max === null; - } + export default defineComponent({ + name: 'EditableNumberRangeFilter', + xModule: facetsXModule.name, + props: { + /** + * The filter data to render and edit. + * + * @public + */ + filter: { + type: Object as PropType, + required: true + }, + /** + * If `instant` prop is true, the needed events are emitted immediately; else, apply button is + * rendered to confirm to do it. False by default. + * + * @public + */ + isInstant: Boolean, + /** + * If `clear` prop is true, clear button, which sets to null component min and max values, is + * rendered. True by default. + * + * @public + */ + hasClearButton: { + type: Boolean, + default: true + }, + /** Class inherited by content element. */ + inputsClass: String, + /** Class inherited by content element. */ + buttonsClass: String + }, + setup: function (props) { + const $x = use$x(); + + const rangeFilterMin = 'minimum amount'; + const rangeFilterMax = 'maximum amount'; + /** + * Component min value. + * + * @internal + */ + const min: Ref = ref(null); + /** + * Component max value. + * + * @internal + */ + const max: Ref = ref(null); + + /** + * Returns {@link @empathyco/x-types#RangeValue} with component min and max + * values. + * + * @returns Range value object with component values. + * + * @internal + */ + const range = computed((): RangeValue => { + return { min: min.value, max: max.value }; + }); + + /** + * It checks if component min and max values are valid. + * + * @returns True if there is any error in the component min and max values. + * + * @internal + */ + const hasError = computed( + () => min.value !== null && max.value !== null && min.value > max.value + ); + + /** + * It checks if component min and max values are different from the ones within the filter + * provided as property. + * + * @returns True if they are different. + * + * @internal + */ + const areValuesDifferent = computed( + () => min.value !== props.filter.range.min || max.value !== props.filter.range.max + ); + + /** + * Dynamic CSS classes. + * + * @returns Object which contains dynamic CSS classes. + * + * @internal + */ + const cssClasses = computed(() => { + return { 'x-editable-number-range-filter--error': hasError.value }; + }); + + /** + * Checks if the range of the filter allows any value, which happens when the min is + * null or 0 and the max is null. + * + * @returns True if the range of the filter allows any value. + * + * @internal + */ + const isAnyRange = computed(() => !min.value && max.value === null); + + /** + * It returns true if the property `hasClearButton` is true and there are values to clear. + * + * @returns True if the clear button has to be rendered. + * + * @internal + */ + const renderClearButton = computed(() => props.hasClearButton && !isAnyRange.value); + + /** + * It emits {@link FacetsXEvents.UserModifiedEditableNumberRangeFilter} event if there are no + * errors and component `min` and `max` values are different than `filter.range` ones. + * + * @internal + */ + const emitUserModifiedFilter = () => { + if (!hasError.value && areValuesDifferent.value) { + $x.emit('UserModifiedEditableNumberRangeFilter', { + ...props.filter, + range: range.value + }); + } + }; - /** - * It returns the number if possible or null otherwise. - * - * @param value - Value. - * @returns The element value as a number if possible or null. - * - * @internal - */ - protected parseRangeValue(value: number): number | null { - return isNaN(value) ? null : value; - } + /** + * It returns the number if possible or null otherwise. + * + * @param value - Value. + * @returns The element value as a number if possible or null. + * + * @internal + */ + const parseRangeValue = (value: number) => (isNaN(value) ? null : value); + + /** + * `min` setter. + * + * @param value - The component `min` value to be set. + * + * @internal + */ + const setMin = (value: number) => { + min.value = parseRangeValue(value); + }; - /** - * `min` setter. - * - * @param value - The component `min` value to be set. - * - * @internal - */ - protected setMin(value: number): void { - this.min = this.parseRangeValue(value); - } + /** + * `max` setter. + * + * @param value - The component `max` value to be set. + * + * @internal + */ + const setMax = (value: number) => { + max.value = parseRangeValue(value); + }; - /** - * `max` setter. - * - * @param value - The component `max` value to be set. - * - * @internal - */ - protected setMax(value: number): void { - this.max = this.parseRangeValue(value); - } + /** + * It sets component `min` and `max` values to null , and it emits the change if component is + * working in instant mode. + * + * @internal + */ + const clearValues = () => { + min.value = null; + max.value = null; + }; - /** - * It sets component `min` and `max` values to null , and it emits the change if component is - * working in instant mode. - * - * @internal - */ - protected clearValues(): void { - this.min = null; - this.max = null; - } + /** + * It resets the min/max range values to null if the + * {@link FacetsXEvents.UserClickedClearAllFilters} event is fired. + * + * @public + */ + $x.on('UserClickedClearAllFilters', false).subscribe(clearValues); + + /** + * It watches the filter range values passed as property and updates component range values if + * they change. + * + * @param newRange - New range value. + * + * @internal + */ + watch( + () => props.filter.range, + (newRange: RangeValue) => { + min.value = newRange.min; + max.value = newRange.max; + }, + { immediate: true, deep: true } + ); + + /** + * It watches range values in order to emit the event with the change if `isInstant` + * property is true. + * + * @internal + */ + watch( + range, + () => { + if (props.isInstant) { + emitUserModifiedFilter(); + } + }, + { deep: true } + ); - /** - * It emits {@link FacetsXEvents.UserModifiedEditableNumberRangeFilter} event if there are no - * errors and component `min` and `max` values are different than `filter.range` ones. - * - * @internal - */ - protected emitUserModifiedFilter(): void { - if (!this.hasError && this.areValuesDifferent) { - this.$x.emit('UserModifiedEditableNumberRangeFilter', { - ...this.filter, - range: this.range - }); - } + return { + rangeFilterMin, + rangeFilterMax, + cssClasses, + min, + max, + setMin, + setMax, + emitUserModifiedFilter, + clearValues, + hasError, + isAnyRange, + renderClearButton + }; } - - protected rangeFilterMin = 'minimum amount'; - protected rangeFilterMax = 'maximum amount'; - } + });