Merge branch 'dev' into 6629-addressObservation
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Robert Ferrús 2024-11-28 06:37:53 +00:00
commit 85b3c3033a
9 changed files with 165 additions and 90 deletions

View File

@ -47,11 +47,13 @@ const onDataSaved = (...args) => {
:label="t('Name')"
v-model="data.name"
:rules="validate('city.name')"
required
/>
<VnSelectProvince
:province-selected="$props.provinceSelected"
:country-fk="$props.countryFk"
v-model="data.provinceFk"
required
/>
</VnRow>
</template>

View File

@ -1,5 +1,5 @@
<script setup>
import { reactive, ref } from 'vue';
import { computed, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
@ -23,11 +23,10 @@ const postcodeFormData = reactive({
});
const townsFetchDataRef = ref(false);
const countriesFetchDataRef = ref(false);
const countriesRef = ref(false);
const townsRef = ref(false);
const provincesFetchDataRef = ref(false);
const countriesOptions = ref([]);
const provincesOptions = ref([]);
const townsOptions = ref([]);
const town = ref({});
const townFilter = ref({});
const countryFilter = ref({});
@ -42,7 +41,7 @@ function onDataSaved(formData) {
({ id }) => id === formData.provinceFk
);
newPostcode.province = provinceObject?.name;
const countryObject = countriesOptions.value.find(
const countryObject = countriesRef.value.opts.find(
({ id }) => id === formData.countryFk
);
newPostcode.country = countryObject?.name;
@ -70,49 +69,8 @@ async function setCountry(countryFk, data) {
data.countryFk = countryFk;
}
async function filterTowns(name) {
if (name !== '') {
townFilter.value.where = {
name: {
like: `%${name}%`,
},
};
await townsFetchDataRef.value?.fetch();
}
}
async function filterCountries(name) {
if (name !== '') {
countryFilter.value.where = {
name: {
like: `%${name}%`,
},
};
await countriesFetchDataRef.value?.fetch();
}
}
async function fetchTowns(countryFk) {
if (!countryFk) return;
townFilter.value.where = {
provinceFk: {
inq: provincesOptions.value.map(({ id }) => id),
},
};
await townsFetchDataRef.value?.fetch();
}
async function handleProvinces(data) {
provincesOptions.value = data;
if (postcodeFormData.countryFk) {
await fetchTowns(postcodeFormData.countryFk);
}
}
async function handleTowns(data) {
townsOptions.value = data;
}
async function handleCountries(data) {
countriesOptions.value = data;
}
async function setProvince(id, data) {
@ -128,6 +86,14 @@ async function onProvinceCreated(data) {
});
postcodeFormData.provinceFk = data.id;
}
const whereTowns = computed(() => {
return {
provinceFk: {
inq: provincesOptions.value.map(({ id }) => id),
},
};
});
</script>
<template>
@ -139,24 +105,6 @@ async function onProvinceCreated(data) {
auto-load
url="Provinces/location"
/>
<FetchData
ref="townsFetchDataRef"
:sort-by="['name ASC']"
:limit="30"
:filter="townFilter"
@on-fetch="handleTowns"
auto-load
url="Towns/location"
/>
<FetchData
ref="countriesFetchDataRef"
:limit="30"
:filter="countryFilter"
:sort-by="['name ASC']"
@on-fetch="handleCountries"
auto-load
url="Countries"
/>
<FormModelPopup
url-create="postcodes"
@ -174,20 +122,26 @@ async function onProvinceCreated(data) {
v-model="data.code"
:rules="validate('postcode.code')"
clearable
required
/>
<VnSelectDialog
ref="townsRef"
:sort-by="['name ASC']"
:limit="30"
auto-load
url="Towns/location"
:where="whereTowns"
:label="t('City')"
@update:model-value="(value) => setTown(value, data)"
@filter="filterTowns"
:tooltip="t('Create city')"
v-model="data.townFk"
:options="townsOptions"
option-label="name"
option-value="id"
:rules="validate('postcode.city')"
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
:emit-value="false"
:clearable="true"
required
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
@ -220,13 +174,18 @@ async function onProvinceCreated(data) {
v-model="data.provinceFk"
@on-province-fetched="handleProvinces"
@on-province-created="onProvinceCreated"
required
/>
<VnSelect
ref="countriesRef"
:limit="30"
:filter="countryFilter"
:sort-by="['name ASC']"
auto-load
url="Countries"
required
:label="t('Country')"
@update:options="handleCountries"
:options="countriesOptions"
hide-selected
@filter="filterCountries"
option-label="name"
option-value="id"
v-model="data.countryFk"

View File

@ -2,7 +2,6 @@
import { computed, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue';
@ -21,15 +20,11 @@ const $props = defineProps({
type: Number,
default: null,
},
provinces: {
type: Array,
default: () => [],
},
});
const autonomiesOptions = ref([]);
const autonomiesRef = ref([]);
const onDataSaved = (dataSaved, requestResponse) => {
requestResponse.autonomy = autonomiesOptions.value.find(
requestResponse.autonomy = autonomiesRef.value.opts.find(
(autonomy) => autonomy.id == requestResponse.autonomyFk
);
emit('onDataSaved', dataSaved, requestResponse);
@ -43,16 +38,6 @@ const where = computed(() => {
</script>
<template>
<FetchData
@on-fetch="(data) => (autonomiesOptions = data)"
auto-load
:filter="{
where,
}"
url="Autonomies/location"
:sort-by="['name ASC']"
:limit="30"
/>
<FormModelPopup
:title="t('New province')"
:subtitle="t('Please, ensure you put the correct data!')"
@ -67,10 +52,17 @@ const where = computed(() => {
:label="t('Name')"
v-model="data.name"
:rules="validate('province.name')"
required
/>
<VnSelect
required
ref="autonomiesRef"
auto-load
:where="where"
url="Autonomies/location"
:sort-by="['name ASC']"
:limit="30"
:label="t('Autonomy')"
:options="autonomiesOptions"
hide-selected
option-label="name"
option-value="id"

View File

@ -273,6 +273,7 @@ function sanitizer(params) {
:key="chip.label"
:removable="!unremovableParams?.includes(chip.label)"
@remove="remove(chip.label)"
data-cy="vnFilterPanelChip"
>
<slot name="tags" :tag="chip" :format-fn="formatValue">
<div class="q-gutter-x-xs">

View File

@ -49,7 +49,7 @@ const getSelectedTagValues = async (tag) => {
<template>
<QForm @submit="applyTags()" class="all-pointer-events">
<QCard class="q-pa-sm column q-pa-lg">
<QCard class="q-pa-sm column q-pa-lg" data-cy="catalogFilterValueDialog">
<VnSelect
:label="t('params.tag')"
v-model="selectedTag"
@ -63,6 +63,7 @@ const getSelectedTagValues = async (tag) => {
:emit-value="false"
use-input
@update:model-value="getSelectedTagValues"
data-cy="catalogFilterValueDialogTagSelect"
/>
<div
v-for="(value, index) in tagValues"
@ -93,6 +94,7 @@ const getSelectedTagValues = async (tag) => {
:disable="!value"
is-outlined
class="col"
data-cy="catalogFilterValueDialogValueInput"
/>
<QBtn
icon="delete"

View File

@ -98,7 +98,7 @@ watch(
/>
</QScrollArea>
</QDrawer>
<QPage class="column items-center q-pa-md">
<QPage class="column items-center q-pa-md" data-cy="orderCatalogPage">
<div class="full-width">
<VnPaginate
:data-key="dataKey"
@ -118,6 +118,7 @@ watch(
:item="row"
is-catalog
class="fill-icon"
data-cy="orderCatalogItem"
/>
</div>
</template>

View File

@ -178,6 +178,7 @@ function addOrder(value, field, params) {
? resetCategory(params, searchFn)
: removeTagGroupParam(params, searchFn, valIndex)
"
data-cy="catalogFilterCustomTag"
>
<strong v-if="customTag.label === 'categoryFk' && categoryList">
{{
@ -211,6 +212,7 @@ function addOrder(value, field, params) {
:name="category.icon"
class="category-icon"
@click="selectCategory(params, category, searchFn)"
data-cy="catalogFilterCategory"
>
<QTooltip>
{{ t(category.name) }}
@ -234,6 +236,7 @@ function addOrder(value, field, params) {
sort-by="name ASC"
:disable="!params.categoryFk"
@update:model-value="searchFn()"
data-cy="catalogFilterType"
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
@ -285,6 +288,7 @@ function addOrder(value, field, params) {
:is-clearable="false"
v-model="searchByTag"
@keyup.enter="(val) => onSearchByTag(val, params)"
data-cy="catalogFilterValueInput"
>
<template #prepend>
<QIcon name="search" />
@ -297,6 +301,7 @@ function addOrder(value, field, params) {
color="primary"
size="md"
dense
data-cy="catalogFilterValueDialogBtn"
/>
<QPopupProxy>
<CatalogFilterValueDialog

View File

@ -0,0 +1,112 @@
/// <reference types="cypress" />
describe('OrderCatalog', () => {
beforeEach(() => {
cy.login('developer');
cy.viewport(1920, 720);
cy.visit('/#/order/8/catalog');
});
const checkCustomFilterTag = (filterName = 'Plant') => {
cy.dataCy('catalogFilterCustomTag').should('exist');
cy.dataCy('catalogFilterCustomTag').contains(filterName);
};
const checkFilterTag = (filterName = 'Plant') => {
cy.dataCy('vnFilterPanelChip').should('exist');
cy.dataCy('vnFilterPanelChip').contains(filterName);
};
const selectCategory = (categoryIndex = 1, categoryName = 'Plant') => {
cy.get(
`div.q-page-container div:nth-of-type(${categoryIndex}) > [data-cy='catalogFilterCategory']`
).should('exist');
cy.get(
`div.q-page-container div:nth-of-type(${categoryIndex}) > [data-cy='catalogFilterCategory']`
).click();
checkCustomFilterTag(categoryName);
};
const searchByCustomTagInput = (option) => {
cy.dataCy('catalogFilterValueInput').find('input').last().focus();
cy.dataCy('catalogFilterValueInput').find('input').last().type(option);
cy.dataCy('catalogFilterValueInput').find('input').last().type('{enter}');
checkCustomFilterTag(option);
};
const selectTypeFilter = (option) => {
cy.selectOption(
'div.q-page-container div.list > div:nth-of-type(2) div:nth-of-type(3)',
option
);
checkFilterTag(option);
};
it('Shows empty state', () => {
cy.dataCy('orderCatalogPage').should('exist');
cy.dataCy('orderCatalogPage').contains('No data to display');
});
it('filter by category', () => {
selectCategory();
cy.dataCy('orderCatalogItem').should('exist');
});
it('filters by type', () => {
selectCategory();
selectTypeFilter('Anthurium');
});
it('filters by custom value select', () => {
selectCategory();
searchByCustomTagInput('Silver');
});
it('filters by custom value dialog', () => {
Cypress.on('uncaught:exception', (err) => {
if (err.message.includes('canceled')) {
return false;
}
});
selectCategory();
cy.dataCy('catalogFilterValueDialogBtn').should('exist');
cy.dataCy('catalogFilterValueDialogBtn').last().click();
cy.dataCy('catalogFilterValueDialogTagSelect').should('exist');
cy.selectOption("[data-cy='catalogFilterValueDialogTagSelect']", 'Tallos');
cy.dataCy('catalogFilterValueDialogValueInput').find('input').focus();
cy.dataCy('catalogFilterValueDialogValueInput').find('input').type('2');
cy.dataCy('catalogFilterValueDialogValueInput').find('input').type('{enter}');
checkCustomFilterTag('2');
});
it('removes a secondary tag', () => {
selectCategory();
selectTypeFilter('Anthurium');
cy.dataCy('vnFilterPanelChip').should('exist');
cy.get(
"div.q-page-container [data-cy='vnFilterPanelChip'] > i.q-chip__icon--remove"
)
.contains('cancel')
.should('exist');
cy.get(
"div.q-page-container [data-cy='vnFilterPanelChip'] > i.q-chip__icon--remove"
)
.contains('cancel')
.click();
cy.dataCy('vnFilterPanelChip').should('not.exist');
});
it('Removes category tag', () => {
selectCategory();
cy.get(
"div.q-page-container [data-cy='catalogFilterCustomTag'] > i.q-chip__icon--remove"
)
.contains('cancel')
.should('exist');
cy.get(
"div.q-page-container [data-cy='catalogFilterCustomTag'] > i.q-chip__icon--remove"
)
.contains('cancel')
.click();
cy.dataCy('catalogFilterCustomTag').should('not.exist');
});
});

View File

@ -86,9 +86,10 @@ Cypress.Commands.add('getValue', (selector) => {
});
// Fill Inputs
Cypress.Commands.add('selectOption', (selector, option) => {
Cypress.Commands.add('selectOption', (selector, option, timeout) => {
cy.waitForElement(selector);
cy.get(selector).click();
cy.wait(timeout || 1000);
cy.get('.q-menu .q-item').contains(option).click();
});
Cypress.Commands.add('countSelectOptions', (selector, option) => {