feat: refs #7957 open in new tab #1086

Merged
jorgep merged 28 commits from 7957-monitorChanges into dev 2025-01-07 14:38:56 +00:00
7 changed files with 120 additions and 57 deletions

View File

@ -141,13 +141,16 @@ const handleInsertMode = (e) => {
<QIcon <QIcon
name="close" name="close"
size="xs" size="xs"
v-if=" :style="{
Review

Así siempre tiene el mismo ancho

Así siempre tiene el mismo ancho
hover && visibility:
value && hover &&
!$attrs.disabled && value &&
!$attrs.readonly && !$attrs.disabled &&
$props.clearable !$attrs.readonly &&
" $props.clearable
? 'visible'
: 'hidden',
}"
@click=" @click="
() => { () => {
value = null; value = null;

View File

@ -1,14 +1,16 @@
<script setup> <script setup>
import { onMounted, ref, watch } from 'vue'; import { onMounted, ref, computed, watch } from 'vue';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useArrayData } from 'composables/useArrayData'; import { useArrayData } from 'composables/useArrayData';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useStateStore } from 'src/stores/useStateStore'; import { useStateStore } from 'src/stores/useStateStore';
import { useRoute } from 'vue-router';
const quasar = useQuasar(); const quasar = useQuasar();
const { t } = useI18n(); const { t } = useI18n();
const state = useStateStore(); const state = useStateStore();
const route = useRoute();
const props = defineProps({ const props = defineProps({
dataKey: { dataKey: {
@ -83,6 +85,17 @@ if (props.redirect)
}; };
let arrayData = useArrayData(props.dataKey, arrayDataProps); let arrayData = useArrayData(props.dataKey, arrayDataProps);
let store = arrayData.store; let store = arrayData.store;
const to = computed(() => {
const url = { path: route.path, query: { ...(route.query ?? {}) } };
jorgep marked this conversation as resolved Outdated
Outdated
Review

Has mirado si store.currentFilter te valia? Ahi en teoria estan los params sin tratar

Has mirado si store.currentFilter te valia? Ahi en teoria estan los params sin tratar
const searchUrl = arrayData.store.searchUrl;

Por defecto vn-input pone null y esto es un parámetro valido de búsqueda, Para que no se añada hay declararlo como undefined.

Por defecto vn-input pone null y esto es un parámetro valido de búsqueda, Para que no se añada hay declararlo como undefined.
const currentFilter = {
...arrayData.store.currentFilter,
search: searchText.value || undefined,
};
if (searchUrl) url.query[searchUrl] = JSON.stringify(currentFilter);
return url;
});
watch( watch(
() => props.dataKey, () => props.dataKey,
@ -132,23 +145,32 @@ async function search() {
<template> <template>
<Teleport to="#searchbar" v-if="state.isHeaderMounted()"> <Teleport to="#searchbar" v-if="state.isHeaderMounted()">
<QForm @submit="search" id="searchbarForm"> <QForm @submit="search" id="searchbarForm">
<RouterLink
:to="to"
@click="
!$event.shiftKey && !$event.ctrlKey && search();
$refs.input.focus();
"
>
<QIcon
v-if="!quasar.platform.is.mobile"
class="cursor-pointer"
name="search"
size="sm"
>
<QTooltip>{{ t('link') }}</QTooltip>
</QIcon>
</RouterLink>
<VnInput <VnInput

No reconcee ctrl + click o shift + click en un link. No sé porque, con un QInput nativo tampoco funciona.

No reconcee ctrl + click o shift + click en un link. No sé porque, con un QInput nativo tampoco funciona.
id="searchbar" id="searchbar"
ref="input"
v-model.trim="searchText" v-model.trim="searchText"
:placeholder="t(props.label)" :placeholder="t(props.label)"
dense dense
standout
autofocus autofocus
data-cy="vnSearchBar" data-cy="vn-searchbar"
borderless
> >
<template #prepend>
<QIcon
v-if="!quasar.platform.is.mobile"
class="cursor-pointer"
name="search"
@click="search"
/>
</template>
<template #append> <template #append>
<QIcon <QIcon
v-if="props.info && $q.screen.gt.xs" v-if="props.info && $q.screen.gt.xs"
@ -173,20 +195,52 @@ async function search() {
.q-field { .q-field {
transition: width 0.36s; transition: width 0.36s;
} }
</style>
<style lang="scss"> :deep(.q-field__native) {
padding-top: 10px;
padding-left: 5px;
}
:deep(.q-field--dark .q-field__native:focus) {
color: black;
}
:deep(.q-field--focused) {
.q-icon {
color: black;
}
}

Antes cogia los colores de la clase &--standout, si no, no tiene color.

Antes cogia los colores de la clase &--standout, si no, no tiene color.
.cursor-info { .cursor-info {
cursor: help; cursor: help;
} }
#searchbar {
.q-field--standout.q-field--highlighted .q-field__control { .q-form {
display: flex;
align-items: center;
border-radius: 4px;
padding: 0 5px;
background-color: var(--vn-search-color);
&:hover {
background-color: var(--vn-search-color-hover);
}
&:focus-within {
background-color: white; background-color: white;
color: black;
.q-field__native,
.q-icon { .q-icon {
color: black !important; color: black;
} }
} }
} }
.q-icon {
color: var(--vn-label-color);
}
</style> </style>
<i18n>
en:
link: click to search, ctrl + click to open in a new tab, shift + click to open in a new window
es:
link: clic para buscar, ctrl + clic para abrir en una nueva pestaña, shift + clic para abrir en una nueva ventana
</i18n>

View File

@ -76,26 +76,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
cancelRequest(); cancelRequest();
canceller = new AbortController(); canceller = new AbortController();
const { params, limit } = getCurrentFilter();
const filter = {
limit: store.limit,
};
let userParams = { ...store.userParams };
Object.assign(filter, store.userFilter);
let where;
if (filter?.where || store.filter?.where)
where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
Object.assign(filter, store.filter);
filter.where = where;
const params = { filter };
Object.assign(params, userParams);
if (params.filter) params.filter.skip = store.skip;
if (store?.order && typeof store?.order == 'string') store.order = [store.order];
if (store.order?.length) params.filter.order = [...store.order];
else delete params.filter.order;
store.currentFilter = JSON.parse(JSON.stringify(params)); store.currentFilter = JSON.parse(JSON.stringify(params));
delete store.currentFilter.filter.include; delete store.currentFilter.filter.include;
@ -121,7 +102,6 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
params, params,
}); });
const { limit } = filter;
store.hasMoreData = limit && response.data.length >= limit; store.hasMoreData = limit && response.data.length >= limit;
processData(response.data, { map: !!store.mapKey, append }); processData(response.data, { map: !!store.mapKey, append });
@ -291,6 +271,31 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
router.replace(newUrl); router.replace(newUrl);
} }
function getCurrentFilter() {
const filter = {
limit: store.limit,
};
let userParams = { ...store.userParams };
Object.assign(filter, store.userFilter);
let where;
if (filter?.where || store.filter?.where)
where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
Object.assign(filter, store.filter);
filter.where = where;
const params = { filter };
Object.assign(params, userParams);
if (params.filter) params.filter.skip = store.skip;
if (store?.order && typeof store?.order == 'string') store.order = [store.order];
if (store.order?.length) params.filter.order = [...store.order];
else delete params.filter.order;
return { filter, params, limit: filter.limit };
}
function processData(data, { map = true, append = true }) { function processData(data, { map = true, append = true }) {
if (!append) { if (!append) {
store.data = []; store.data = [];
@ -323,6 +328,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
fetch, fetch,
applyFilter, applyFilter,
addFilter, addFilter,
getCurrentFilter,
addFilterWhere, addFilterWhere,
addOrder, addOrder,
deleteOrder, deleteOrder,

View File

@ -10,6 +10,8 @@ body.body--light {
--vn-text-color: black; --vn-text-color: black;
--vn-label-color: #5f5f5f; --vn-label-color: #5f5f5f;
--vn-accent-color: #e7e3e3; --vn-accent-color: #e7e3e3;
--vn-search-color: #d4d4d4;
--vn-search-color-hover: #cfcfcf;
--vn-empty-tag: #acacac; --vn-empty-tag: #acacac;
--vn-black-text-color: black; --vn-black-text-color: black;
--vn-text-color-contrast: white; --vn-text-color-contrast: white;
@ -28,6 +30,8 @@ body.body--dark {
--vn-text-color: white; --vn-text-color: white;
--vn-label-color: #a8a8a8; --vn-label-color: #a8a8a8;
--vn-accent-color: #424242; --vn-accent-color: #424242;
--vn-search-color: #4b4b4b;
--vn-search-color-hover: #5b5b5b;
--vn-empty-tag: #2d2d2d; --vn-empty-tag: #2d2d2d;
--vn-black-text-color: black; --vn-black-text-color: black;
--vn-text-color-contrast: black; --vn-text-color-contrast: black;

View File

@ -41,7 +41,7 @@ describe('OrderCatalog', () => {
} }
}); });
cy.get( cy.get(
'[data-cy="vnSearchBar"] > .q-field > .q-field__inner > .q-field__control' '[data-cy="vn-searchbar"] > .q-field > .q-field__inner > .q-field__control'
).type('{enter}'); ).type('{enter}');
cy.get(':nth-child(1) > [data-cy="catalogFilterCategory"]').click(); cy.get(':nth-child(1) > [data-cy="catalogFilterCategory"]').click();
cy.dataCy('catalogFilterValueDialogBtn').last().click(); cy.dataCy('catalogFilterValueDialogBtn').last().click();

View File

@ -9,9 +9,9 @@ describe('TicketList', () => {
}); });
const searchResults = (search) => { const searchResults = (search) => {
cy.dataCy('vnSearchBar').find('input').focus(); cy.dataCy('vn-searchbar').find('input').focus();
if (search) cy.dataCy('vnSearchBar').find('input').type(search); if (search) cy.dataCy('vn-searchbar').find('input').type(search);
cy.dataCy('vnSearchBar').find('input').type('{enter}'); cy.dataCy('vn-searchbar').find('input').type('{enter}');
cy.dataCy('ticketListTable').should('exist'); cy.dataCy('ticketListTable').should('exist');
cy.get(firstRow).should('exist'); cy.get(firstRow).should('exist');
}; };

View File

@ -274,15 +274,11 @@ Cypress.Commands.add('openLeftMenu', (element) => {
Cypress.Commands.add('clearSearchbar', (element) => { Cypress.Commands.add('clearSearchbar', (element) => {
if (element) cy.waitForElement(element); if (element) cy.waitForElement(element);
cy.get( cy.get('[data-cy="vn-searchbar"]').clear();
'#searchbar > form > div:nth-child(1) > label > div:nth-child(1) input'
).clear();
}); });
Cypress.Commands.add('typeSearchbar', (value) => { Cypress.Commands.add('writeSearchbar', (value) => {
cy.get('#searchbar > form > div:nth-child(1) > label > div:nth-child(1) input').type( cy.get('[data-cy="vn-searchbar"]').type(value);
value
);
}); });
Cypress.Commands.add('validateContent', (selector, expectedValue) => { Cypress.Commands.add('validateContent', (selector, expectedValue) => {