#6891 showRightSideFilterPanel #353

Merged
jorgep merged 48 commits from 6891-showRightSideFilterPanel into dev 2024-05-15 13:39:23 +00:00
47 changed files with 368 additions and 271 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- (Worker) => Se crea la sección Taquilla
- (General) => Se mantiene el filtro lateral en cualquier parte de la seccíon.
### Fixed

View File

@ -0,0 +1,55 @@
<script setup>
Review

Evitamos el uso repetitivo de esta código. Hay secciones como claimAction que tiene un menú lateral derecho personalizado. Con este componente evitamos duplicar el código.

Evitamos el uso repetitivo de esta código. Hay secciones como claimAction que tiene un menú lateral derecho personalizado. Con este componente evitamos duplicar el código.
import { ref, onMounted, useSlots } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore';
const slots = useSlots();
const hasContent = ref(false);
const rightPanel = ref(null);
onMounted(() => {
rightPanel.value = document.querySelector('#right-panel');
if (rightPanel.value.childNodes.length) hasContent.value = true;
// Check if there's content to display
const observer = new MutationObserver(() => {
hasContent.value = rightPanel.value.childNodes.length;
});
if (rightPanel.value)
observer.observe(rightPanel.value, {
subtree: true,
childList: true,
attributes: true,
});
if (!slots['right-panel'] && !hasContent.value) stateStore.rightDrawer = false;
});
const { t } = useI18n();
const stateStore = useStateStore();
</script>
<template>
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
v-if="hasContent || $slots['right-panel']"
flat
@click="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</Teleport>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
<QScrollArea class="fit text-grey-8">
<div id="right-panel"></div>
<slot v-if="!hasContent" name="right-panel" />
</QScrollArea>
</QDrawer>
</template>

View File

@ -1,13 +1,13 @@
<script setup>
import { onBeforeMount, computed, watchEffect } from 'vue';
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useArrayData } from 'src/composables/useArrayData';
import { useStateStore } from 'stores/useStateStore';
import useCardSize from 'src/composables/useCardSize';
import VnSubToolbar from '../ui/VnSubToolbar.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
import LeftMenu from 'components/LeftMenu.vue';
import RightMenu from 'components/common/RightMenu.vue';
const props = defineProps({
dataKey: { type: String, required: true },
@ -15,13 +15,13 @@ const props = defineProps({
customUrl: { type: String, default: undefined },
filter: { type: Object, default: () => {} },
descriptor: { type: Object, required: true },
searchbarDataKey: { type: String, default: undefined },
searchbarUrl: { type: String, default: undefined },
filterPanel: { type: Object, default: undefined },
searchDataKey: { type: String, default: undefined },
searchUrl: { type: String, default: undefined },
searchbarLabel: { type: String, default: '' },
searchbarInfo: { type: String, default: '' },
});
const { t } = useI18n();
const stateStore = useStateStore();
const route = useRoute();
const url = computed(() => {
@ -54,24 +54,31 @@ watchEffect(() => {
});

Añadimos botón "hamburguer" para el menú lateral derecho

Añadimos botón "hamburguer" para el menú lateral derecho
</script>
<template>
<Teleport
to="#searchbar"
v-if="stateStore.isHeaderMounted() && props.searchbarDataKey"
>
<VnSearchbar
:data-key="props.searchbarDataKey"
:url="props.searchbarUrl"
:label="t(props.searchbarLabel)"
:info="t(props.searchbarInfo)"
/>
</Teleport>
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
<QScrollArea class="fit">
<component :is="descriptor" />
<QSeparator />
<LeftMenu source="card" />
</QScrollArea>
</QDrawer>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#searchbar" v-if="props.searchDataKey">
<slot name="searchbar">
<VnSearchbar
:data-key="props.searchDataKey"
:url="props.searchUrl"
:label="props.searchbarLabel"
:info="props.searchbarInfo"
/>
</slot>
</Teleport>
<slot v-else name="searchbar" />
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
<QScrollArea class="fit">
<component :is="descriptor" />
<QSeparator />
<LeftMenu source="card" />
</QScrollArea>
</QDrawer>
<RightMenu>
<template #right-panel v-if="props.filterPanel">
<component :is="props.filterPanel" :data-key="props.searchDataKey" />
</template>
</RightMenu>
</template>
<QPageContainer>
<QPage>
<VnSubToolbar />

View File

@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
import { useArrayData } from 'composables/useArrayData';
import { useRoute } from 'vue-router';
import toDate from 'filters/toDate';
import useRedirect from 'src/composables/useRedirect';
Review

Habilitamos la redirección desde el panel lateral en cualquier sección

Habilitamos la redirección desde el panel lateral en cualquier sección
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
const { t } = useI18n();
@ -56,6 +56,7 @@ const arrayData = useArrayData(props.dataKey, {
const route = useRoute();
const store = arrayData.store;
const userParams = ref({});
const { navigate } = useRedirect();
onMounted(() => {
if (props.params) userParams.value = JSON.parse(JSON.stringify(props.params));
@ -92,6 +93,7 @@ async function search() {
isLoading.value = false;
emit('search');
navigate(store.data, {});
}
async function reload() {
@ -102,6 +104,7 @@ async function reload() {
if (!props.showAll && !params.length) store.data = [];
isLoading.value = false;
emit('refresh');
navigate(store.data, {});
}
async function clearFilters() {

View File

@ -42,6 +42,10 @@ const props = defineProps({
type: Object,
default: null,
},
keepOpts: {
type: Array,
default: () => [],
},
offset: {
type: Number,
default: 0,
@ -76,6 +80,7 @@ const arrayData = useArrayData(props.dataKey, {
order: props.order,
userParams: props.userParams,
exprBuilder: props.exprBuilder,
keepOpts: props.keepOpts,
});
const store = arrayData.store;

View File

@ -1,11 +1,13 @@
<script setup>
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
import { useArrayData } from 'composables/useArrayData';
import VnInput from 'src/components/common/VnInput.vue';
import useRedirect from 'src/composables/useRedirect';
import { useI18n } from 'vue-i18n';
const quasar = useQuasar();
const { t } = useI18n();
const props = defineProps({
dataKey: {
@ -65,10 +67,10 @@ const props = defineProps({
},
});
const router = useRouter();
const arrayData = useArrayData(props.dataKey, { ...props });
const { store } = arrayData;
const searchText = ref('');
const { navigate } = useRedirect();
onMounted(() => {
const params = store.userParams;
@ -91,27 +93,10 @@ async function search() {
if (!props.redirect) return;
if (props.customRouteRedirectName)
return router.push({
name: props.customRouteRedirectName,
params: { id: searchText.value },
});
const { matched: matches } = router.currentRoute.value;
const { path } = matches.at(-1);
const [, moduleName] = path.split('/');
if (!store.data.length || store.data.length > 1)
return router.push({ path: `/${moduleName}/list` });
const targetId = store.data[0].id;
let targetUrl;
if (path.endsWith('/list')) targetUrl = path.replace('/list', `/${targetId}/summary`);
if (path.endsWith('-list')) targetUrl = path.replace('-list', `/${targetId}/summary`);
else if (path.includes(':id')) targetUrl = path.replace(':id', targetId);
await router.push({ path: targetUrl });
navigate(store.data, {
customRouteRedirectName: props.customRouteRedirectName,
searchText: searchText.value,
});
}
</script>
@ -120,7 +105,7 @@ async function search() {
<VnInput
id="searchbar"
v-model="searchText"
:placeholder="props.label"
:placeholder="t(props.label)"
dense
standout
autofocus
@ -139,7 +124,7 @@ async function search() {
name="info"
class="cursor-info"
>
<QTooltip>{{ props.info }}</QTooltip>
<QTooltip>{{ t(props.info) }}</QTooltip>
</QIcon>
</template>
</VnInput>

View File

@ -47,7 +47,10 @@ export function useArrayData(key, userOptions) {
if (isEmpty || !allowedOptions.includes(option)) continue;
if (Object.prototype.hasOwnProperty.call(store, option)) {
store[option] = userOptions[option];
const defaultOpts = userOptions[option];
store[option] = userOptions.keepOpts?.includes(option)
? Object.assign(defaultOpts, store[option])
: defaultOpts;
}
}
}

View File

@ -0,0 +1,25 @@
import { useRouter } from 'vue-router';
export default function useRedirect() {
const router = useRouter();
const navigate = (data, { customRouteRedirectName, searchText }) => {
if (customRouteRedirectName)
return router.push({
name: customRouteRedirectName,
params: { id: searchText },
});
const { matched: matches } = router.currentRoute.value;
const { path } = matches.at(-1);
const to =
data.length === 1
? path.replace(/\/(list|:id)|-list/, `/${data[0].id}`)
: path.replace(/:id.*/, '');
router.push({ path: to });
};
return { navigate };
Review

Así redirigimos a la misma sección! 😄 ej. claim/1/basic-data -> claim/2/basic-data

Así redirigimos a la misma sección! 😄 ej. claim/1/basic-data -> claim/2/basic-data
}

View File

@ -1,34 +1,14 @@
<script setup>
import { onMounted, watch } from 'vue';

Se estaba haciendo un uso de la lógica antigua . Ahora solo se usa VnCard

Se estaba haciendo un uso de la lógica antigua . Ahora solo se usa VnCard
import { useRoute } from 'vue-router';
import { useArrayData } from 'src/composables/useArrayData';
import AgencyDescriptor from 'pages/Agency/Card/AgencyDescriptor.vue';
import VnCard from 'components/common/VnCard.vue';
const route = useRoute();
const arrayData = useArrayData('Agency', {
url: `Agencies/${route.params.id}`,
});
const { store } = arrayData;
onMounted(async () => await arrayData.fetch({ append: false }));
watch(
() => route.params.id,
async (newId) => {
if (newId) {
store.url = `Agencies/${newId}`;
await arrayData.fetch({ append: false });
}
}
);
</script>
<template>
<VnCard
data-key="Agency"
base-url="Agencies"
:descriptor="AgencyDescriptor"
searchbar-data-key="AgencyList"
searchbar-url="Agencies"
search-data-key="AgencyList"
search-url="Agencies"
searchbar-label="agency.searchBar.label"
searchbar-info="agency.searchBar.info"
/>

View File

@ -15,8 +15,8 @@ const props = defineProps({
});
const { t } = useI18n();
const { params } = useRoute();
const entityId = computed(() => props.id || params.id);
const route = useRoute();
const entityId = computed(() => props.id || route.params.id);
Review

Params no es reactivo, solo useRoute(), por lo que no actualizaba correctamente el id.

Params no es reactivo, solo useRoute(), por lo que no actualizaba correctamente el id.
const { store } = useArrayData('Parking');
const card = computed(() => store.data);
</script>

View File

@ -3,11 +3,9 @@ import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import FetchData from 'src/components/FetchData.vue';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'components/ui/VnLv.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
const $props = defineProps({
id: {
@ -15,9 +13,9 @@ const $props = defineProps({
default: 0,
},
});
const { params } = useRoute();

Lo mismo que en AgencyDescriptor.

Lo mismo que en AgencyDescriptor.
const route = useRoute();
const { t } = useI18n();
const entityId = computed(() => $props.id || params.id);
const entityId = computed(() => $props.id || route.params.id);
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],

View File

@ -201,30 +201,7 @@ async function post(query, params) {
auto-load
@on-fetch="(data) => (destinationTypes = data)"
/>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
flat
@click="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</Teleport>
</template>
<QDrawer
v-model="stateStore.rightDrawer"
side="right"
:width="300"
show-if-above
v-if="claim"
>
<Teleport to="#right-panel" v-if="stateStore.isHeaderMounted() && claim">
Review

Añadimos el contenido personalizado al panel lateral.

Añadimos el contenido personalizado al panel lateral.
<QCard class="totalClaim q-my-md q-pa-sm no-box-shadow">
{{ `${t('Total claimed')}: ${toCurrency(totalClaimed)}` }}
</QCard>
@ -274,7 +251,7 @@ async function post(query, params) {
v-model="multiplicatorValue"
/>
</QCard>
</QDrawer>
</Teleport>
<Teleport to="#st-data" v-if="stateStore.isSubToolbarShown()"> </Teleport>
<CrudModel
v-if="claim"

View File

@ -1,14 +1,16 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import ClaimDescriptor from './ClaimDescriptor.vue';
import ClaimFilter from '../ClaimFilter.vue';
</script>
<template>
<VnCard
data-key="Claim"
base-url="Claims"
:descriptor="ClaimDescriptor"
searchbar-data-key="ClaimList"
searchbar-url="Claims/filter"
:filter-panel="ClaimFilter"
search-data-key="ClaimList"
search-url="Claims/filter"
searchbar-label="Search claim"
searchbar-info="You can search by claim id or customer name"
/>

View File

@ -1,14 +1,16 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import CustomerDescriptor from './CustomerDescriptor.vue';
import CustomerFilter from '../CustomerFilter.vue';
</script>
<template>
<VnCard
data-key="Client"
base-url="Clients"
:descriptor="CustomerDescriptor"
searchbar-data-key="CustomerList"
searchbar-url="Clients/filter"
:filter-panel="CustomerFilter"
search-data-key="CustomerList"
search-url="Clients/filter"
searchbar-label="Search customer"
searchbar-info="You can search by customer id or name"
/>

View File

@ -1,14 +1,16 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import EntryDescriptor from './EntryDescriptor.vue';
import EntryFilter from '../EntryFilter.vue';
</script>
<template>
<VnCard
data-key="Entry"
base-url="Entries"
:descriptor="EntryDescriptor"
searchbar-data-key="EntryList"
searchbar-url="Entries/filter"
:filter-panel="EntryFilter"
search-data-key="EntryList"
search-url="Entries/filter"
searchbar-label="Search entries"
searchbar-info="You can search by entry reference"
/>

View File

@ -3,14 +3,13 @@ import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import axios from 'axios';
import { useArrayData } from 'src/composables/useArrayData';
import { downloadFile } from 'src/composables/downloadFile';
import FormModel from 'components/FormModel.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'src/components/FetchData.vue';
import axios from 'axios';
import VnRow from 'src/components/ui/VnRow.vue';
const quasar = useQuasar();
const route = useRoute();
@ -181,7 +180,7 @@ async function upsert() {
:auto-load="true"
>
<template #form="{ data }">
<div class="row q-gutter-md q-mb-md">
<VnRow>
Review

En alguna subida a dev, se ha desajustado el diseño de invoiceInBasicData, lo arreglo rapidamente en esta rama. apunto el tiempo en esta rama: #6942 . Cambiaré los qinput por vninput en la rama correspondiente.

En alguna subida a dev, se ha desajustado el diseño de invoiceInBasicData, lo arreglo rapidamente en esta rama. apunto el tiempo en esta rama: #6942 . Cambiaré los qinput por vninput en la rama correspondiente.
<VnSelect
:label="t('supplierFk')"
v-model="data.supplierFk"
@ -208,8 +207,8 @@ async function upsert() {
:label="t('Supplier ref')"
v-model="data.supplierRef"
/>
</div>
<div class="row q-gutter-md q-mb-md">
</VnRow>
<VnRow>
<QInput
:label="t('Expedition date')"
v-model="data.issued"
@ -264,8 +263,8 @@ async function upsert() {
</QIcon>
</template>
</QInput>
</div>
<div class="row q-gutter-md q-mb-md">
</VnRow>
<VnRow>
<QInput
:label="t('Undeductible VAT')"
v-model="data.deductibleExpenseFk"
@ -318,8 +317,8 @@ async function upsert() {
</QBtn>
</template>
</QInput>
</div>
<div class="row q-gutter-md q-mb-md">
</VnRow>
<VnRow>
<QInput
:label="t('Entry date')"
v-model="data.bookEntried"
@ -378,8 +377,8 @@ async function upsert() {
</QIcon>
</template>
</QInput>
</div>
<div class="row q-gutter-md q-mb-md">
</VnRow>
<VnRow>
<VnSelect
:label="t('Currency')"
v-model="data.currencyFk"
@ -395,13 +394,8 @@ async function upsert() {
option-value="id"
option-label="code"
/>
</div>
<div class="row q-gutter-md q-mb-md">
<QCheckbox
:label="t('invoiceIn.summary.booked')"
v-model="data.isBooked"
/>
</div>
</VnRow>
<QCheckbox :label="t('invoiceIn.summary.booked')" v-model="data.isBooked" />
</template>
</FormModel>
<QDialog ref="editDmsRef">

View File

@ -1,6 +1,7 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import InvoiceInDescriptor from './InvoiceInDescriptor.vue';
import InvoiceInFilter from '../InvoiceInFilter.vue';
const filter = {
include: [
@ -25,8 +26,9 @@ const filter = {
base-url="InvoiceIns"
:filter="filter"
:descriptor="InvoiceInDescriptor"
searchbar-data-key="InvoiceInList"
searchbar-url="InvoiceIns/filter"
:filter-panel="InvoiceInFilter"
search-data-key="InvoiceInList"
search-url="InvoiceIns/filter"
searchbar-label="Search invoice"
searchbar-info="You can search by invoice reference"
/>

View File

@ -1,14 +1,16 @@
<script setup>
import InvoiceOutDescriptor from './InvoiceOutDescriptor.vue';
import VnCard from 'components/common/VnCard.vue';
import InvoiceOutFilter from '../InvoiceOutFilter.vue';
</script>
<template>
<VnCard
data-key="InvoiceOut"
base-url="InvoiceOuts"
:descriptor="InvoiceOutDescriptor"
searchbar-data-key="InvoiceOutList"
searchbar-url="InvoiceOuts/filter"
:filter-panel="InvoiceOutFilter"
search-data-key="InvoiceOutList"
search-url="InvoiceOuts/filter"
searchbar-label="Search invoice"
searchbar-info="You can search by invoice reference"
/>

View File

@ -1,7 +1,17 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import ItemDescriptor from './ItemDescriptor.vue';
import ItemListFilter from '../ItemListFilter.vue';
</script>
<template>
<VnCard data-key="Item" base-url="Items" :descriptor="ItemDescriptor" />
<VnCard
data-key="Item"
base-url="Items"
:descriptor="ItemDescriptor"
:filter-panel="ItemListFilter"
search-data-key="ItemList"
search-url="Items/filter"
searchbar-label="searchbar.label"
searchbar-info="searchbar.info"
/>
</template>

View File

@ -457,6 +457,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
:limit="12"
:expr-builder="exprBuilder"
:user-params="params"
:keep-opts="['userParams']"
:offset="50"
auto-load
>

View File

@ -7,8 +7,7 @@ import VnLv from 'src/components/ui/VnLv.vue';
import CardList from 'src/components/ui/CardList.vue';
import ItemTypeSummary from 'src/pages/ItemType/Card/ItemTypeSummary.vue';
import ItemTypeFilter from 'src/pages/ItemType/ItemTypeFilter.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import ItemTypeSearchbar from '../ItemType/ItemTypeSearchbar.vue';
import { useStateStore } from 'stores/useStateStore';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
@ -63,13 +62,7 @@ const exprBuilder = (param, value) => {
<template>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#searchbar">
<VnSearchbar
data-key="ItemTypeList"
url="ItemTypes"
:label="t('Search item type')"
:info="t('Search itemType by id, name or code')"
:expr-builder="exprBuilder"
/>
<ItemTypeSearchbar />
</Teleport>
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
@ -132,11 +125,3 @@ const exprBuilder = (param, value) => {
</QTooltip>
</QPageSticky>
</template>
<i18n>
es:
New item type: Nueva familia
Name: Nombre
Search item type: Buscar familia
Search itemType by id, name or code: Buscar familia por id, nombre o código
</i18n>

View File

@ -78,3 +78,6 @@ itemTags:
tag: Tag
value: Value
relevancy: Relevancy
searchbar:
label: Search item
info: Search by item id

View File

@ -78,3 +78,6 @@ itemTags:
tag: Etiqueta
value: Valor
relevancy: Relevancia
searchbar:
label: Buscar artículo
info: Buscar por id de artículo

View File

@ -1,12 +1,20 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import ItemTypeDescriptor from 'src/pages/ItemType/Card/ItemTypeDescriptor.vue';
import ItemTypeFilter from 'src/pages/ItemType/ItemTypeFilter.vue';
import ItemTypeSearchbar from '../ItemTypeSearchbar.vue';
</script>
<template>
<VnCard
data-key="ItemTypeSummary"
base-url="ItemTypes"
:descriptor="ItemTypeDescriptor"
/>
:filter-panel="ItemTypeFilter"
search-data-key="ItemTypeList"
search-url="ItemTypes"
>
<template #searchbar>
<ItemTypeSearchbar />
</template>
</VnCard>
</template>

View File

@ -0,0 +1,19 @@
<script setup>
import VnSearchbar from 'components/ui/VnSearchbar.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>
<template>
<VnSearchbar
data-key="ItemTypeList"
url="ItemTypes"
:label="t('Search item type')"
:info="t('Search itemType by id, name or code')"
/>
</template>
<i18n>
es:
Search item type: Buscar familia
Search itemType by id, name or code: Buscar familia por id, nombre o código
</i18n>

View File

@ -1,7 +1,19 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue';
import OrderFilter from './OrderFilter.vue';
import OrderSearchbar from './OrderSearchbar.vue';
</script>
<template>
<VnCard data-key="Order" base-url="Orders" :descriptor="OrderDescriptor" />
<VnCard
data-key="Order"
base-url="Orders"
:descriptor="OrderDescriptor"
:filter-panel="OrderFilter"
search-data-key="OrderList"
>
<template #searchbar>
<OrderSearchbar />
</template>
</VnCard>
</template>

View File

@ -7,7 +7,6 @@ import { dashIfEmpty, toCurrency, toDateHourMinSec } from 'src/filters';
import VnLv from 'components/ui/VnLv.vue';
import CardSummary from 'components/ui/CardSummary.vue';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import OrderSearchbar from 'pages/Order/Card/OrderSearchbar.vue';
import FetchedTags from 'components/ui/FetchedTags.vue';
const { t } = useI18n();
@ -53,10 +52,6 @@ const detailsColumns = ref([
</script>
<template>
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
<OrderSearchbar />
</Teleport>
<div class="q-pa-md">
<CardSummary ref="summary" :url="`Orders/${entityId}/summary`">
<template #header="{ entity }">
@ -158,11 +153,7 @@ const detailsColumns = ref([
<p class="header">
{{ t('order.summary.details') }}
</p>
<QTable
:columns="detailsColumns"
:rows="entity?.rows"
flat
>
<QTable :columns="detailsColumns" :rows="entity?.rows" flat>
<template #header="props">
<QTr :props="props">
<QTh auto-width>{{ t('order.summary.item') }}</QTh>

View File

@ -61,6 +61,7 @@ function navigate(id) {
:limit="20"
:order="['landed DESC', 'clientFk', 'id DESC']"
:user-params="{ showEmpty: false }"
:keep-opts="['userParams']"
auto-load
>
<template #body="{ rows }">

View File

@ -1,5 +1,5 @@
<script setup>
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import VnRow from 'components/ui/VnRow.vue';
@ -10,7 +10,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
const { t } = useI18n();
const route = useRoute();
const parkingId = route.params?.id || null;
const parkingId = computed(() => route.params?.id || null);
const sectors = ref([]);
const sectorFilter = { fields: ['id', 'description'] };

View File

@ -1,6 +1,7 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import ParkingDescriptor from 'pages/Parking/Card/ParkingDescriptor.vue';
import ParkingFilter from 'pages/Parking/ParkingFilter.vue';
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],
@ -13,8 +14,9 @@ const filter = {
base-url="Parkings"
:filter="filter"
:descriptor="ParkingDescriptor"
searchbar-data-key="ParkingList"
searchbar-url="Parkings"
:filter-panel="ParkingFilter"
search-data-key="ParkingList"
search-url="Parkings"
searchbar-label="parking.searchBar.label"
searchbar-info="parking.searchBar.info"
/>

View File

@ -15,10 +15,10 @@ const props = defineProps({
});
const { t } = useI18n();
const { params } = useRoute();
const entityId = computed(() => props.id || params.id);
const route = useRoute();
const entityId = computed(() => props.id || route.params.id);
const { store } = useArrayData('Parking');
const card = computed(() => store.data);
const parking = computed(() => store.data);
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
@ -29,11 +29,12 @@ const filter = {
module="Parking"
data-key="Parking"
:url="`Parkings/${entityId}`"
:title="card?.code"
:subtitle="card?.id"
:title="parking?.code"
:subtitle="parking?.id"
:filter="filter"
@on-fetch="(data) => (parking = data)"
Review

Cuando se abre un descriptor hay que obetner los datos así. Estaba fallando la reactividad(no se actualizaba el id correctamente), esto lo corrige.

Cuando se abre un descriptor hay que obetner los datos así. Estaba fallando la reactividad(no se actualizaba el id correctamente), esto lo corrige.
>
<template #body="{ entity: parking }">
<template #body>
<VnLv :label="t('globals.code')" :value="parking.code" />
<VnLv :label="t('parking.pickingOrder')" :value="parking.pickingOrder" />
<VnLv :label="t('parking.sector')" :value="parking.sector?.description" />

View File

@ -1,9 +1,10 @@
<script setup>
import { computed } from 'vue';
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'components/ui/VnLv.vue';
import { useArrayData } from 'src/composables/useArrayData';
const $props = defineProps({
id: {
@ -14,7 +15,9 @@ const $props = defineProps({
const router = useRoute();
const { t } = useI18n();
const entityId = computed(() => $props.id || router.params.id);
const { store } = useArrayData('Parking');
const parking = ref(store.data);
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
@ -23,9 +26,13 @@ const filter = {
<template>
<div class="q-pa-md">
<CardSummary :url="`Parkings/${entityId}`" :filter="filter">
<template #header="{ entity: parking }">{{ parking.code }}</template>
<template #body="{ entity: parking }">
<CardSummary
Review

Cuando se abre un descriptor hay que obetner los datos así. Estaba fallando la reactividad(no se actualizaba el id correctamente), esto lo corrige.

Cuando se abre un descriptor hay que obetner los datos así. Estaba fallando la reactividad(no se actualizaba el id correctamente), esto lo corrige.
:url="`Parkings/${entityId}`"
:filter="filter"
@on-fetch="(data) => (parking = data)"
>
<template #header>{{ parking.code }}</template>
<template #body>
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<a

View File

@ -1,7 +1,19 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import RouteDescriptor from 'pages/Route/Card/RouteDescriptor.vue';
import RouteFilter from './RouteFilter.vue';
import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue';
</script>
<template>
<VnCard data-key="Route" base-url="Routes" :descriptor="RouteDescriptor" />
<VnCard
data-key="Route"
base-url="Routes"
:descriptor="RouteDescriptor"
:filter-panel="RouteFilter"
search-data-key="RouteList"
>
<template #searchbar>
<RouteSearchbar />
</template>
</VnCard>
</template>

View File

@ -1,6 +1,6 @@
<script setup>
import VnSearchbar from 'components/ui/VnSearchbar.vue';
import {useI18n} from "vue-i18n";
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>

View File

@ -10,7 +10,6 @@ import { dashIfEmpty, toCurrency, toDate, toHour } from 'src/filters';
import WorkerDescriptorProxy from 'pages/Worker/Card/WorkerDescriptorProxy.vue';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue';
import { openBuscaman } from 'src/utils/buscaman';
const $props = defineProps({
@ -118,11 +117,6 @@ const ticketColumns = ref([
</script>
<template>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#searchbar">
<RouteSearchbar />
</Teleport>
</template>
<div class="q-pa-md full-width">
<CardSummary
ref="summary"

View File

@ -1,7 +1,19 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import ShelvingDescriptor from 'pages/Shelving/Card/ShelvingDescriptor.vue';
import ShelvingFilter from './ShelvingFilter.vue';
import ShelvingSearchbar from './ShelvingSearchbar.vue';
</script>
<template>
<VnCard data-key="Shelving" base-url="Shelvings" :descriptor="ShelvingDescriptor" />
<VnCard
data-key="Shelving"
base-url="Shelvings"
:descriptor="ShelvingDescriptor"
:filter-panel="ShelvingFilter"
search-data-key="ShelvingList"
>
<template #searchbar>
<ShelvingSearchbar />
</template>
</VnCard>
</template>

View File

@ -1,14 +1,16 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import SupplierDescriptor from './SupplierDescriptor.vue';
import SupplierListFilter from '../SupplierListFilter.vue';
</script>
<template>
<VnCard
data-key="Supplier"
base-url="Suppliers"
:descriptor="SupplierDescriptor"
searchbar-data-key="SupplierList"
searchbar-url="Suppliers/filter"
:filter-panel="SupplierListFilter"
search-data-key="SupplierList"
search-url="Suppliers/filter"
searchbar-label="Search suppliers"
/>
</template>

View File

@ -1,14 +1,16 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import TicketDescriptor from './TicketDescriptor.vue';
import TicketFilter from '../TicketFilter.vue';
</script>
<template>
<VnCard
data-key="Ticket"
base-url="Tickets"
:descriptor="TicketDescriptor"
searchbar-data-key="TicketList"
searchbar-url="Tickets/filter"
:filter-panel="TicketFilter"
search-data-key="TicketList"
search-url="Tickets/filter"
searchbar-label="Search ticket"
searchbar-info="You can search by ticket id or alias"
/>

View File

@ -1,14 +1,16 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
import WorkerDescriptor from './WorkerDescriptor.vue';
import WorkerFilter from '../WorkerFilter.vue';
</script>
<template>
<VnCard
data-key="Worker"
base-url="Workers"
:descriptor="WorkerDescriptor"
searchbar-data-key="WorkerList"
searchbar-url="Workers/filter"
:filter-panel="WorkerFilter"
search-data-key="WorkerList"
search-url="Workers/filter"
searchbar-label="Search worker"
searchbar-info="You can search by worker id or name"
/>

View File

@ -1,7 +1,8 @@
/// <reference types="cypress" />
Review

Arreglar test de e2e

Arreglar test de e2e
describe('InvoiceInBasicData', () => {
const selects = '.q-form .q-card>:nth-child(1) > :nth-child(1) > .q-field';
const appendBtns = 'label button';
const formInputs = '.q-form > .q-card input';
const firstFormSelect = '.q-card > .vn-row:nth-child(1) > .q-select';
const appendBtns = '.q-form label button';
const dialogAppendBtns = '.q-dialog label button';
const dialogInputs = '.q-dialog input';
const dialogActionBtns = '.q-card__actions button';
@ -12,15 +13,14 @@ describe('InvoiceInBasicData', () => {
});
it('should edit the provideer and supplier ref', () => {
cy.selectOption(selects, 'Bros');
cy.selectOption(firstFormSelect, 'Bros');
cy.get('[title="Reset"]').click();
cy.get(appendBtns).eq(0).click();
cy.get('input').eq(2).type(4739);
cy.get(formInputs).eq(1).type(4739);
cy.saveCard();
cy.get(`${selects} input`).eq(0).invoke('val').should('eq', 'Plants nick');
cy.get('input').eq(2).invoke('val').should('eq', '4739');
cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Plants nick');
cy.get(formInputs).eq(1).invoke('val').should('eq', '4739');
});
it('should edit the dms data', () => {

View File

@ -1,6 +1,6 @@
/// <reference types="cypress" />
Review

Arreglar test de e2e.

Arreglar test de e2e.
describe('InvoiceInDueDay', () => {
const inputs = 'label input';
const amountInput = 'tbody > tr:nth-child(1) td:nth-child(4)';
const addBtn = '.q-page-sticky > div > .q-btn > .q-btn__content';
beforeEach(() => {
@ -9,7 +9,7 @@ describe('InvoiceInDueDay', () => {
});
it('should update the amount', () => {
cy.get(inputs).eq(3).type(23);
cy.get(amountInput).type('{selectall}{backspace}23');
cy.saveCard();
cy.get('.q-notification__message').should('have.text', 'Data saved');
});

View File

@ -17,10 +17,7 @@ describe('InvoiceInIntrastat', () => {
cy.saveCard();
cy.visit(`/#/invoice-in/1/intrastat`);
cy.getValue(firstLineCode).should(
'equal',
'Plantas vivas: Esqueje/injerto, Vid'
);
cy.getValue(firstLineCode).should('equal', 'Plantas vivas: Esqueje/injerto, Vid');
});
it('should add a new row', () => {
@ -33,6 +30,6 @@ describe('InvoiceInIntrastat', () => {
});
it('should remove the first line', () => {
cy.removeRow(1);
cy.removeRow(2);
});
});

View File

@ -29,7 +29,7 @@ describe('InvoiceInVat', () => {
});
Review

Arreglar test de e2e.

Arreglar test de e2e.
it('should remove the first line', () => {
cy.removeRow(1);
cy.removeRow(2);
});
it('should throw an error if there are fields undefined', () => {

View File

@ -1,6 +1,6 @@
/// <reference types="cypress" />
describe('Ticket descriptor', () => {
const toCloneOpt = '.q-list > :nth-child(5)';
const toCloneOpt = '[role="menu"] .q-list > :nth-child(5)';
Review

Arreglar test de e2e.

Arreglar test de e2e.
const warehouseValue = ':nth-child(1) > :nth-child(6) > .value > span';
const summaryHeader = '.summaryHeader > div';

View File

@ -1,6 +1,6 @@
describe('WorkerList', () => {
const workerId = 1110;
const lockerCode = '200A';
const workerId = 1109;
const lockerCode = '201A';
Review

Arreglar test de e2e.

Arreglar test de e2e.
const input = '.q-card input';
const firstOpt = '[role="listbox"] .q-item:nth-child(1)';
beforeEach(() => {

View File

@ -1,62 +0,0 @@
import { vi, describe, expect, it, beforeAll, afterEach, beforeEach } from 'vitest';

Ahora se hace la redirección en el composable useRedirect

Ahora se hace la redirección en el composable useRedirect
import { createWrapper } from 'app/test/vitest/helper';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
// Probar a importar como plugin vue-router en archivo helper
describe('VnSearchBar', () => {
let vm;
let wrapper;
let pushSpy;
beforeAll(() => {
wrapper = createWrapper(VnSearchbar, {
propsData: {
dataKey: 'CustomerList',
label: 'Search customer',
info: 'Info customer',
},
});
vm = wrapper.vm;
vm.router.currentRoute.value.matched = [
{
path: '/',
},
{
path: '/customer',
},
{
path: '/customer/:id',
},
{
path: '/customer/:id/basic-data',
},
];
pushSpy = vi.spyOn(vm.router, 'push');
vi.spyOn(vm.arrayData, 'applyFilter');
});
beforeEach(() => (vm.store.data = [{ id: 1112, name: 'Trash' }]));
afterEach(() => vi.clearAllMocks());
it('should be defined', async () => {
expect(vm.searchText).toBeDefined();
expect(vm.searchText).toEqual('');
});
it('should redirect to list page if there are several results', async () => {
vm.store.data.push({ id: 1, name: 'employee' });
await vm.search();
expect(pushSpy).toHaveBeenCalledWith({ path: '/customer/list' });
});
it('should redirect to list page if there is no results', async () => {
vm.store.data.pop();
await vm.search();
expect(pushSpy).toHaveBeenCalledWith({ path: '/customer/list' });
});
it('should redirect to basic-data page if there is only one result', async () => {
await vm.search();
expect(pushSpy).toHaveBeenCalledWith({ path: '/customer/1112/basic-data' });
});
});

View File

@ -0,0 +1,52 @@
import { vi, describe, expect, it, beforeEach, beforeAll } from 'vitest';
import useRedirect from 'src/composables/useRedirect';
import { useRouter } from 'vue-router';
vi.mock('vue-router');
describe('useRedirect', () => {
useRouter.mockReturnValue({
push: vi.fn(),
currentRoute: {
value: {
matched: [
{ path: '/' },
{ path: '/customer' },
{ path: '/customer/:id' },
{ path: '/customer/:id/basic-data' },
],
},
},
});
const data = [];
let navigate;
let spy;
beforeAll(() => {
const { navigate: navigateFn } = useRedirect();
navigate = navigateFn;
spy = useRouter().push;
});
beforeEach(() => {
data.length = 0;
spy.mockReset();
});
it('should redirect to list page if there are several results', async () => {
data.push({ id: 1, name: 'employee' }, { id: 2, name: 'boss' });
navigate(data, {});
expect(spy).toHaveBeenCalledWith({ path: '/customer/' });
});
it('should redirect to list page if there is no results', async () => {
navigate(data, {});
expect(spy).toHaveBeenCalledWith({ path: '/customer/' });
});
it('should redirect to basic-data page if there is only one result', async () => {
data.push({ id: 1, name: 'employee' });
navigate(data, {});
expect(spy).toHaveBeenCalledWith({ path: '/customer/1/basic-data' });
});
});