#8449 - vnLogFilter #1640
|
@ -70,7 +70,7 @@ function textAlignToFlex(textAlign) {
|
|||
:style="textAlignToFlex(align)"
|
||||
>
|
||||
<span :title="label">{{ label }}</span>
|
||||
<div v-if="name && model?.index">
|
||||
<div v-if="name">
|
||||
jorgep marked this conversation as resolved
|
||||
<QChip
|
||||
:label="!vertical ? model?.index : ''"
|
||||
:icon="
|
||||
|
@ -83,14 +83,14 @@ function textAlignToFlex(textAlign) {
|
|||
:size="vertical ? '' : 'sm'"
|
||||
:class="[
|
||||
model?.index ? 'color-vn-text' : 'bg-transparent',
|
||||
vertical ? 'q-px-none' : '',
|
||||
vertical ? 'q-mx-none q-py-lg' : '',
|
||||
jorgep marked this conversation as resolved
alexm
commented
Arreglado estilo del hover: Arreglado estilo del hover:
https://redmine.verdnatura.es/issues/8449#note-10
|
||||
]"
|
||||
class="no-box-shadow"
|
||||
:clickable="true"
|
||||
style="min-width: 40px; max-height: 30px"
|
||||
>
|
||||
<div
|
||||
class="column flex-center"
|
||||
class="column justify-center text-center"
|
||||
alexm
commented
// //
jorgep
commented
No entiendo este comentario. Supongo que quieres decir que va relacionado con el anterior No entiendo este comentario. Supongo que quieres decir que va relacionado con el anterior
|
||||
v-if="vertical"
|
||||
:style="!model?.index && 'color: #5d5d5d'"
|
||||
>
|
||||
|
|
|
@ -26,7 +26,12 @@ function columnName(col) {
|
|||
}
|
||||
</script>
|
||||
<template>
|
||||
<VnFilterPanel v-bind="$attrs" :search-button="true" :disable-submit-event="true">
|
||||
<VnFilterPanel
|
||||
v-bind="$attrs"
|
||||
:search-button="true"
|
||||
:disable-submit-event="true"
|
||||
:search-url
|
||||
>
|
||||
<template #body="{ params, orders, searchFn }">
|
||||
<div
|
||||
class="container"
|
||||
|
@ -34,13 +39,20 @@ function columnName(col) {
|
|||
:key="col.id"
|
||||
>
|
||||
<div class="filter">
|
||||
<VnFilter
|
||||
ref="tableFilterRef"
|
||||
:column="col"
|
||||
:data-key="$attrs['data-key']"
|
||||
v-model="params[columnName(col)]"
|
||||
:search-url="searchUrl"
|
||||
/>
|
||||
<slot
|
||||
:name="`filter-${col.name}`"
|
||||
:params="params"
|
||||
:column-name="columnName(col)"
|
||||
:search-fn
|
||||
>
|
||||
<VnFilter
|
||||
ref="tableFilterRef"
|
||||
:column="col"
|
||||
:data-key="$attrs['data-key']"
|
||||
v-model="params[columnName(col)]"
|
||||
:search-url="searchUrl"
|
||||
/>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="order">
|
||||
<VnTableOrder
|
||||
|
@ -77,13 +89,13 @@ function columnName(col) {
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 45px;
|
||||
min-height: 45px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.filter {
|
||||
width: 70%;
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.order {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, onUnmounted, watch } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import axios from 'axios';
|
||||
|
@ -11,11 +11,11 @@ import { useCapitalize } from 'src/composables/useCapitalize';
|
|||
import { useValidator } from 'src/composables/useValidator';
|
||||
import VnAvatar from '../ui/VnAvatar.vue';
|
||||
import VnLogValue from './VnLogValue.vue';
|
||||
import FetchData from '../FetchData.vue';
|
||||
import VnSelect from './VnSelect.vue';
|
||||
import VnUserLink from '../ui/VnUserLink.vue';
|
||||
import VnPaginate from '../ui/VnPaginate.vue';
|
||||
import VnLogFilter from 'src/components/common/VnLogFilter.vue';
|
||||
import RightMenu from './RightMenu.vue';
|
||||
import { useFilterParams } from 'src/composables/useFilterParams';
|
||||
|
||||
const stateStore = useStateStore();
|
||||
const validationsStore = useValidator();
|
||||
|
@ -72,39 +72,8 @@ const filter = {
|
|||
};
|
||||
|
||||
const paginate = ref();
|
||||
const actions = ref();
|
||||
jorgep marked this conversation as resolved
Outdated
alexm
commented
Se quita (casi) todo lo referente a los filtros, ya que se mueve a VnLogFilter Se quita (casi) todo lo referente a los filtros, ya que se mueve a VnLogFilter
|
||||
const changeInput = ref();
|
||||
const searchInput = ref();
|
||||
const userRadio = ref();
|
||||
const userSelect = ref();
|
||||
const dateFrom = ref();
|
||||
const dateFromDialog = ref(false);
|
||||
const dateTo = ref();
|
||||
const dateToDialog = ref(false);
|
||||
const selectedFilters = ref({});
|
||||
const userTypes = [
|
||||
{ label: 'All', value: undefined },
|
||||
{ label: 'User', value: { neq: null } },
|
||||
{ label: 'System', value: null },
|
||||
];
|
||||
const checkboxOptions = ref({
|
||||
insert: {
|
||||
label: 'Creates',
|
||||
selected: false,
|
||||
},
|
||||
update: {
|
||||
label: 'Edits',
|
||||
selected: false,
|
||||
},
|
||||
delete: {
|
||||
label: 'Deletes',
|
||||
selected: false,
|
||||
},
|
||||
select: {
|
||||
label: 'Accesses',
|
||||
selected: false,
|
||||
},
|
||||
});
|
||||
const dataKey = computed(() => `${props.model}Log`);
|
||||
const userParams = ref(useFilterParams(dataKey.value).params);
|
||||
|
||||
let validations = models;
|
||||
let pointRecord = ref(null);
|
||||
|
@ -246,131 +215,54 @@ async function setLogTree(data) {
|
|||
function filterByRecord(modelLog) {
|
||||
byRecord.value = true;
|
||||
const { id, model } = modelLog;
|
||||
|
||||
searchInput.value = id;
|
||||
selectedFilters.value.changedModelId = id;
|
||||
selectedFilters.value.changedModel = model;
|
||||
applyFilter();
|
||||
applyFilter({ changedModelId: id, changedModel: model });
|
||||
}
|
||||
|
||||
async function applyFilter() {
|
||||
filter.where = { and: [] };
|
||||
if (
|
||||
!selectedFilters.value.changedModel ||
|
||||
(!selectedFilters.value.changedModelValue &&
|
||||
!selectedFilters.value.changedModelId)
|
||||
)
|
||||
byRecord.value = false;
|
||||
|
||||
if (!byRecord.value) filter.where.and.push({ originFk: route.params.id });
|
||||
|
||||
if (Object.keys(selectedFilters.value).length) {
|
||||
filter.where.and.push(selectedFilters.value);
|
||||
}
|
||||
|
||||
paginate.value.fetch({ filter });
|
||||
async function applyFilter(params = {}) {
|
||||
paginate.value.arrayData.applyFilter({
|
||||
filter: {},
|
||||
params: { originFk: route.params.id, ...params },
|
||||
});
|
||||
}
|
||||
|
||||
function setDate(type) {
|
||||
let from = dateFrom.value
|
||||
? date.formatDate(dateFrom.value.split('-').reverse().join('-'), 'YYYY-MM-DD')
|
||||
: undefined;
|
||||
from = date.adjustDate(from, { hour: 0, minute: 0, second: 0, millisecond: 0 }, true);
|
||||
|
||||
let to = dateTo.value
|
||||
? date.formatDate(dateTo.value.split('-').reverse().join('-'), 'YYYY-MM-DD')
|
||||
: date.formatDate(dateFrom.value.split('-').reverse().join('-'), 'YYYY-MM-DD');
|
||||
to = date.adjustDate(
|
||||
to,
|
||||
{ hour: 21, minute: 59, second: 59, millisecond: 999 },
|
||||
true,
|
||||
);
|
||||
|
||||
switch (type) {
|
||||
case 'from':
|
||||
return { between: [from, to] };
|
||||
case 'to': {
|
||||
if (dateFrom.value) {
|
||||
function exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'changedModelValue':
|
||||
return { [param]: { like: `%${value}%` } };
|
||||
case 'change':
|
||||
if (value)
|
||||
return {
|
||||
between: [from, to],
|
||||
or: [
|
||||
{ oldJson: { like: `%${value}%` } },
|
||||
{ newJson: { like: `%${value}%` } },
|
||||
{ description: { like: `%${value}%` } },
|
||||
],
|
||||
};
|
||||
}
|
||||
return { lte: to };
|
||||
}
|
||||
break;
|
||||
case 'action':
|
||||
if (value?.length) return { [param]: { inq: value } };
|
||||
break;
|
||||
jorgep marked this conversation as resolved
alexm
commented
Ponemos bien el Ponemos bien el `exprBuilder`
|
||||
case 'from':
|
||||
return { creationDate: { gte: value } };
|
||||
case 'to':
|
||||
return { creationDate: { lte: value } };
|
||||
case 'userType':
|
||||
if (value === 'User') return { userFk: { neq: null } };
|
||||
if (value === 'System') return { userFk: null };
|
||||
break;
|
||||
default:
|
||||
return { [param]: value };
|
||||
}
|
||||
}
|
||||
|
||||
function selectFilter(type, dateType) {
|
||||
const filter = {};
|
||||
const actions = { inq: [] };
|
||||
let reload = true;
|
||||
|
||||
if (type === 'search') {
|
||||
if (/^\s*[0-9]+\s*$/.test(searchInput.value) || props.byRecord) {
|
||||
selectedFilters.value.changedModelId = searchInput.value.trim();
|
||||
} else if (!searchInput.value) {
|
||||
selectedFilters.value.changedModelId = undefined;
|
||||
selectedFilters.value.changedModelValue = undefined;
|
||||
} else {
|
||||
selectedFilters.value.changedModelValue = { like: `%${searchInput.value}%` };
|
||||
}
|
||||
}
|
||||
if (type === 'action' && selectedFilters.value.changedModel === null) {
|
||||
selectedFilters.value.changedModel = undefined;
|
||||
}
|
||||
if (type === 'userRadio') {
|
||||
selectedFilters.value.userFk = userRadio.value;
|
||||
}
|
||||
if (type === 'change') {
|
||||
if (changeInput.value)
|
||||
selectedFilters.value.or = [
|
||||
{ oldJson: { like: `%${changeInput.value}%` } },
|
||||
{ newJson: { like: `%${changeInput.value}%` } },
|
||||
{ description: { like: `%${changeInput.value}%` } },
|
||||
];
|
||||
else selectedFilters.value.or = undefined;
|
||||
}
|
||||
if (type === 'userSelect') {
|
||||
selectedFilters.value.userFk =
|
||||
userSelect.value !== null ? userSelect.value : undefined;
|
||||
}
|
||||
if (type === 'date') {
|
||||
if (!dateFrom.value && !dateTo.value) {
|
||||
selectedFilters.value.creationDate = undefined;
|
||||
} else if (dateType === 'to') {
|
||||
selectedFilters.value.creationDate = setDate('to');
|
||||
} else if (dateType === 'from') {
|
||||
selectedFilters.value.creationDate = setDate('from');
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(checkboxOptions.value).forEach((key) => {
|
||||
if (checkboxOptions.value[key].selected) actions.inq.push(key);
|
||||
});
|
||||
selectedFilters.value.action = actions.inq.length ? actions : undefined;
|
||||
|
||||
Object.keys(selectedFilters.value).forEach((key) => {
|
||||
if (selectedFilters.value[key]) filter[key] = selectedFilters.value[key];
|
||||
});
|
||||
|
||||
if (reload) applyFilter(filter);
|
||||
}
|
||||
|
||||
async function clearFilter() {
|
||||
selectedFilters.value = {};
|
||||
byRecord.value = false;
|
||||
userSelect.value = undefined;
|
||||
searchInput.value = undefined;
|
||||
changeInput.value = undefined;
|
||||
dateFrom.value = undefined;
|
||||
dateTo.value = undefined;
|
||||
userRadio.value = undefined;
|
||||
Object.keys(checkboxOptions.value).forEach(
|
||||
(opt) => (checkboxOptions.value[opt].selected = false),
|
||||
);
|
||||
await applyFilter();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
stateStore.rightDrawerChangeValue(true);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
stateStore.rightDrawer = false;
|
||||
});
|
||||
|
@ -383,32 +275,18 @@ watch(
|
|||
);
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
:url="`${props.model}Logs/${route.params.id}/models`"
|
||||
:filter="{ order: ['changedModel'] }"
|
||||
@on-fetch="
|
||||
(data) =>
|
||||
(actions = data.map((item) => {
|
||||
const changedModel = item.changedModel;
|
||||
return {
|
||||
locale: useCapitalize(
|
||||
validations[changedModel]?.locale?.name ?? changedModel,
|
||||
),
|
||||
value: changedModel,
|
||||
};
|
||||
}))
|
||||
"
|
||||
auto-load
|
||||
/>
|
||||
<VnPaginate
|
||||
ref="paginate"
|
||||
:data-key="`${model}Log`"
|
||||
:url="`${model}Logs`"
|
||||
:data-key
|
||||
:url="dataKey + 's'"
|
||||
jorgep marked this conversation as resolved
alexm
commented
VnLog es una seccion que se suele filtra, creo que vale la pena que se muestre de primeras VnLog es una seccion que se suele filtra, creo que vale la pena que se muestre de primeras
|
||||
:user-filter="filter"
|
||||
:skeleton="false"
|
||||
auto-load
|
||||
@on-fetch="setLogTree"
|
||||
@on-change="setLogTree"
|
||||
search-url="logs"
|
||||
:exprBuilder
|
||||
:order="['creationDate DESC', 'id DESC']"
|
||||
>
|
||||
<template #body>
|
||||
<div
|
||||
|
@ -467,6 +345,7 @@ watch(
|
|||
backgroundColor: useColor(modelLog.model),
|
||||
}"
|
||||
:title="`${modelLog.model} #${modelLog.id}`"
|
||||
data-cy="vnLog-model-chip"
|
||||
>
|
||||
{{ t(modelLog.modelI18n) }}
|
||||
</QChip>
|
||||
|
@ -580,6 +459,7 @@ watch(
|
|||
}`,
|
||||
)
|
||||
"
|
||||
data-cy="vnLog-action-icon"
|
||||
/>
|
||||
</div>
|
||||
</QItem>
|
||||
|
@ -697,181 +577,12 @@ watch(
|
|||
</VnPaginate>
|
||||
<RightMenu>
|
||||
<template #right-panel>
|
||||
<QList dense>
|
||||
<QSeparator />
|
||||
<QItem class="q-mt-sm">
|
||||
<QInput
|
||||
:label="t('globals.search')"
|
||||
v-model="searchInput"
|
||||
class="full-width"
|
||||
clearable
|
||||
filled
|
||||
clear-icon="close"
|
||||
@keyup.enter="() => selectFilter('search')"
|
||||
@focusout="() => selectFilter('search')"
|
||||
@clear="() => selectFilter('search')"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{ t('tooltips.search') }}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelect
|
||||
class="full-width"
|
||||
:label="t('globals.entity')"
|
||||
v-model="selectedFilters.changedModel"
|
||||
option-label="locale"
|
||||
option-value="value"
|
||||
filled
|
||||
:options="actions"
|
||||
@update:model-value="selectFilter('action')"
|
||||
hide-selected
|
||||
/>
|
||||
</QItem>
|
||||
<QItem class="q-mt-sm">
|
||||
<QOptionGroup
|
||||
size="sm"
|
||||
v-model="userRadio"
|
||||
:options="userTypes"
|
||||
color="primary"
|
||||
@update:model-value="selectFilter('userRadio')"
|
||||
right-label
|
||||
>
|
||||
<template #label="{ label }">
|
||||
{{ t(`Users.${label}`) }}
|
||||
</template>
|
||||
</QOptionGroup>
|
||||
</QItem>
|
||||
<QItem class="q-mt-sm">
|
||||
<QItemSection v-if="userRadio !== null">
|
||||
<VnSelect
|
||||
class="full-width"
|
||||
:label="t('globals.user')"
|
||||
v-model="userSelect"
|
||||
filled
|
||||
:url="`${model}Logs/${route.params.id}/editors`"
|
||||
:fields="['id', 'nickname', 'name', 'image']"
|
||||
sort-by="nickname"
|
||||
@update:model-value="selectFilter('userSelect')"
|
||||
hide-selected
|
||||
>
|
||||
<template #option="{ opt, itemProps }">
|
||||
<QItem
|
||||
v-bind="itemProps"
|
||||
class="q-pa-xs row items-center"
|
||||
>
|
||||
<QItemSection class="col-3 items-center">
|
||||
<VnAvatar :worker-id="opt.id" />
|
||||
</QItemSection>
|
||||
<QItemSection class="col-9 justify-center">
|
||||
<span>{{ opt.name }}</span>
|
||||
<span class="text-grey">{{ opt.nickname }}</span>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem class="q-mt-sm">
|
||||
<QInput
|
||||
:label="t('globals.changes')"
|
||||
v-model="changeInput"
|
||||
class="full-width"
|
||||
filled
|
||||
clearable
|
||||
clear-icon="close"
|
||||
@keyup.enter="selectFilter('change')"
|
||||
@focusout="selectFilter('change')"
|
||||
@clear="selectFilter('change')"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip max-width="250px">{{
|
||||
t('tooltips.changes')
|
||||
}}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItem>
|
||||
<QItem
|
||||
:class="index == 'create' ? 'q-mt-md' : 'q-mt-xs'"
|
||||
v-for="(checkboxOption, index) in checkboxOptions"
|
||||
:key="index"
|
||||
>
|
||||
<QCheckbox
|
||||
size="sm"
|
||||
v-model="checkboxOption.selected"
|
||||
:label="t(`actions.${checkboxOption.label}`)"
|
||||
@update:model-value="selectFilter"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem class="q-mt-sm">
|
||||
<QInput
|
||||
class="full-width"
|
||||
:label="t('globals.date')"
|
||||
@click="dateFromDialog = true"
|
||||
@focus="(evt) => evt.target.blur()"
|
||||
@clear="selectFilter('date', 'to')"
|
||||
v-model="dateFrom"
|
||||
clearable
|
||||
filled
|
||||
clear-icon="close"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem class="q-mt-sm">
|
||||
<QInput
|
||||
class="full-width"
|
||||
:label="t('globals.to')"
|
||||
@click="dateToDialog = true"
|
||||
@focus="(evt) => evt.target.blur()"
|
||||
@clear="selectFilter('date', 'from')"
|
||||
v-model="dateTo"
|
||||
clearable
|
||||
filled
|
||||
clear-icon="close"
|
||||
/>
|
||||
</QItem>
|
||||
</QList>
|
||||
<VnLogFilter :data-key />
|
||||
</template>
|
||||
</RightMenu>
|
||||
<QDialog v-model="dateFromDialog">
|
||||
<QDate
|
||||
:years-in-month-view="false"
|
||||
v-model="dateFrom"
|
||||
dense
|
||||
flat
|
||||
minimal
|
||||
filled
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
dateFromDialog = false;
|
||||
dateFrom = date.formatDate(value, 'DD-MM-YYYY');
|
||||
selectFilter('date', 'from');
|
||||
}
|
||||
"
|
||||
/>
|
||||
</QDialog>
|
||||
<QDialog v-model="dateToDialog">
|
||||
<QDate
|
||||
v-model="dateTo"
|
||||
dense
|
||||
flat
|
||||
minimal
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
dateToDialog = false;
|
||||
dateTo = date.formatDate(value, 'DD-MM-YYYY');
|
||||
selectFilter('date', 'to');
|
||||
}
|
||||
"
|
||||
/>
|
||||
</QDialog>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn
|
||||
v-if="Object.values(selectedFilters).some((filter) => filter !== undefined)"
|
||||
v-if="Object.keys(userParams).some((filter) => filter !== 'originFk')"
|
||||
color="primary"
|
||||
icon="filter_alt_off"
|
||||
size="md"
|
||||
|
|
|
@ -1,77 +1,249 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
import VnTableFilter from '../VnTable/VnTableFilter.vue';
|
||||
import VnSelect from './VnSelect.vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import VnInput from './VnInput.vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import VnInputDate from './VnInputDate.vue';
|
||||
import { useFilterParams } from 'src/composables/useFilterParams';
|
||||
import FetchData from '../FetchData.vue';
|
||||
import { useValidator } from 'src/composables/useValidator';
|
||||
import { useCapitalize } from 'src/composables/useCapitalize';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
const $props = defineProps({
|
||||
dataKey: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const workers = ref();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const validationsStore = useValidator();
|
||||
const { models } = validationsStore;
|
||||
const entities = ref([]);
|
||||
const editors = ref([]);
|
||||
const userParams = ref(useFilterParams($props.dataKey).params);
|
||||
let validations = models;
|
||||
const userTypes = [
|
||||
{ value: 'All', label: t(`Users.All`) },
|
||||
{ value: 'User', label: t(`Users.User`) },
|
||||
{ value: 'System', label: t(`Users.System`) },
|
||||
];
|
||||
const checkboxOptions = ref([
|
||||
{ name: 'insert', label: 'Creates', selected: false },
|
||||
{ name: 'update', label: 'Edits', selected: false },
|
||||
{ name: 'delete', label: 'Deletes', selected: false },
|
||||
{ name: 'select', label: 'Accesses', selected: false },
|
||||
]);
|
||||
const columns = computed(() => [
|
||||
{ name: 'changedModelValue' },
|
||||
{ name: 'changedModel' },
|
||||
{ name: 'userType', orderBy: false },
|
||||
{ name: 'userFk' },
|
||||
{ name: 'change', orderBy: false },
|
||||
{ name: 'action' },
|
||||
{ name: 'from', orderBy: 'creationDate' },
|
||||
{ name: 'to', orderBy: 'creationDate' },
|
||||
]);
|
||||
|
||||
const userParamsWatcher = watch(
|
||||
() => userParams.value,
|
||||
(params) => {
|
||||
if (params.action) {
|
||||
params.action.forEach((option) => {
|
||||
checkboxOptions.value.find((o) => o.name === option).selected = true;
|
||||
});
|
||||
userParamsWatcher();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function getActions() {
|
||||
const actions = checkboxOptions.value
|
||||
.filter((option) => option.selected)
|
||||
?.map((o) => o.name);
|
||||
return actions.length ? actions : null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Workers/activeWithInheritedRole"
|
||||
:filter="{ where: { role: 'salesPerson' } }"
|
||||
@on-fetch="(data) => (workers = data)"
|
||||
:url="`${dataKey}s/${route.params.id}/models`"
|
||||
:filter="{ order: ['changedModel'] }"
|
||||
@on-fetch="
|
||||
(data) =>
|
||||
(entities = data.map((item) => {
|
||||
const changedModel = item.changedModel;
|
||||
return {
|
||||
locale: useCapitalize(
|
||||
validations[changedModel]?.locale?.name ?? changedModel,
|
||||
),
|
||||
value: changedModel,
|
||||
};
|
||||
}))
|
||||
"
|
||||
auto-load
|
||||
/>
|
||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||
<span>{{ formatFn(tag.value) }}</span>
|
||||
<FetchData
|
||||
:url="`${dataKey}s/${route.params.id}/editors`"
|
||||
:filter="{ fields: ['id', 'nickname', 'name', 'image'] }"
|
||||
sort-by="nickname"
|
||||
@on-fetch="(data) => (editors = data)"
|
||||
auto-load
|
||||
/>
|
||||
<VnTableFilter
|
||||
v-if="dataKey"
|
||||
:data-key
|
||||
:columns="columns"
|
||||
:redirect="false"
|
||||
:hiddenTags="['originFk', 'creationDate']"
|
||||
:exprBuilder
|
||||
search-url="logs"
|
||||
:showTagChips="false"
|
||||
>
|
||||
<template #filter-changedModelValue="{ params, columnName, searchFn }">
|
||||
<VnInput
|
||||
:label="t('globals.search')"
|
||||
v-model="params[columnName]"
|
||||
@keyup.enter="searchFn"
|
||||
@blur="searchFn"
|
||||
@remove="searchFn"
|
||||
:info="t('tooltips.search')"
|
||||
dense
|
||||
filled
|
||||
data-cy="vnLog-search"
|
||||
/>
|
||||
</template>
|
||||
<template #filter-changedModel="{ params, columnName, searchFn }">
|
||||
<VnSelect
|
||||
:label="t('globals.entity')"
|
||||
v-model="params[columnName]"
|
||||
option-label="locale"
|
||||
option-value="value"
|
||||
:options="entities"
|
||||
@update:model-value="() => searchFn()"
|
||||
dense
|
||||
filled
|
||||
data-cy="vnLog-entity"
|
||||
/>
|
||||
</template>
|
||||
<template #filter-userType="{ params, columnName, searchFn }">
|
||||
<QOptionGroup
|
||||
class="text-left"
|
||||
size="sm"
|
||||
v-model="params[columnName]"
|
||||
:options="userTypes"
|
||||
color="primary"
|
||||
@update:model-value="
|
||||
() => {
|
||||
params.userFk = null;
|
||||
searchFn();
|
||||
}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #filter-userFk="{ params, columnName, searchFn }">
|
||||
<VnSelect
|
||||
:label="t('globals.user')"
|
||||
v-model="params[columnName]"
|
||||
:options="editors"
|
||||
@update:modelValue="() => searchFn()"
|
||||
:disable="params.userType === 'System'"
|
||||
dense
|
||||
filled
|
||||
>
|
||||
<template #option="{ opt, itemProps }">
|
||||
<QItem v-bind="itemProps" class="q-pa-xs row items-center">
|
||||
<QItemSection class="col-3 items-center">
|
||||
<VnAvatar :worker-id="opt.id" />
|
||||
</QItemSection>
|
||||
<QItemSection class="col-9 justify-center">
|
||||
<span>{{ opt.name }}</span>
|
||||
<span class="text-grey">{{ opt.nickname }}</span>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</template>
|
||||
<template #filter-change="{ params, columnName, searchFn }">
|
||||
<VnInput
|
||||
:label="t('globals.changes')"
|
||||
v-model="params[columnName]"
|
||||
@keyup.enter="searchFn"
|
||||
@blur="searchFn"
|
||||
@remove="searchFn"
|
||||
:info="t('tooltips.changes')"
|
||||
dense
|
||||
filled
|
||||
/>
|
||||
</template>
|
||||
<template #filter-action="{ searchFn }">
|
||||
<div class="column">
|
||||
<QCheckbox
|
||||
v-for="checkboxOption in checkboxOptions"
|
||||
:key="checkboxOption"
|
||||
size="sm"
|
||||
v-model="checkboxOption.selected"
|
||||
:label="t(`actions.${checkboxOption.label}`)"
|
||||
@update:model-value="
|
||||
() => searchFn(undefined, 'action', getActions())
|
||||
"
|
||||
data-cy="vnLog-checkbox"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #body="{ params, searchFn }">
|
||||
<QDate
|
||||
v-model="params.created"
|
||||
@update:model-value="searchFn()"
|
||||
<template #filter-from="{ params, columnName, searchFn }">
|
||||
<VnInputDate
|
||||
:label="t('globals.from')"
|
||||
v-model="params[columnName]"
|
||||
dense
|
||||
flat
|
||||
minimal
|
||||
>
|
||||
</QDate>
|
||||
<QSeparator />
|
||||
<QItem>
|
||||
<QItemSection v-if="!workers">
|
||||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="workers">
|
||||
<QSelect
|
||||
:label="t('User')"
|
||||
v-model="params.userFk"
|
||||
@update:model-value="searchFn()"
|
||||
:options="workers"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
emit-value
|
||||
map-options
|
||||
use-input
|
||||
:input-debounce="0"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
filled
|
||||
@update:modelValue="() => searchFn()"
|
||||
/>
|
||||
</template>
|
||||
</VnFilterPanel>
|
||||
<template #filter-to="{ params, columnName, searchFn }">
|
||||
<VnInputDate
|
||||
:label="t('globals.to')"
|
||||
v-model="params[columnName]"
|
||||
dense
|
||||
filled
|
||||
@update:modelValue="() => searchFn()"
|
||||
/>
|
||||
</template>
|
||||
</VnTableFilter>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
params:
|
||||
search: Contains
|
||||
userFk: User
|
||||
created: Created
|
||||
es:
|
||||
tooltips:
|
||||
search: Buscar por identificador o concepto
|
||||
changes: Buscar por cambios. Los atributos deben buscarse por su nombre interno, para obtenerlo situar el cursor sobre el atributo.
|
||||
actions:
|
||||
Creates: Crea
|
||||
Edits: Modifica
|
||||
Deletes: Elimina
|
||||
Accesses: Accede
|
||||
Users:
|
||||
User: Usuario
|
||||
All: Todo
|
||||
System: Sistema
|
||||
params:
|
||||
search: Contiene
|
||||
userFk: Usuario
|
||||
created: Creada
|
||||
User: Usuario
|
||||
changedModel: Entity
|
||||
|
||||
en:
|
||||
tooltips:
|
||||
search: Search by identifier or concept
|
||||
changes: Search by changes. Attributes must be searched by their internal name, to get it place the cursor over the attribute.
|
||||
actions:
|
||||
Creates: Creates
|
||||
Edits: Edits
|
||||
Deletes: Deletes
|
||||
Accesses: Accesses
|
||||
Users:
|
||||
User: User
|
||||
All: All
|
||||
System: System
|
||||
params:
|
||||
changedModel: Entidad
|
||||
</i18n>
|
||||
|
|
|
@ -108,27 +108,4 @@ describe('VnLog', () => {
|
|||
expect(vm.logTree[0].originFk).toEqual(1);
|
||||
expect(vm.logTree[0].logs[0].user.name).toEqual('salesPerson');
|
||||
});
|
||||
|
||||
it('should correctly set the selectedFilters when filtering', () => {
|
||||
jorgep marked this conversation as resolved
Outdated
alexm
commented
Ya no existe esta logica, al usar VnFilterPanel (por debajo) el se encarga del filtrado Ya no existe esta logica, al usar VnFilterPanel (por debajo) el se encarga del filtrado
|
||||
vm.searchInput = '1';
|
||||
vm.userSelect = '21';
|
||||
vm.checkboxOptions.insert.selected = true;
|
||||
vm.checkboxOptions.update.selected = true;
|
||||
|
||||
vm.selectFilter('search');
|
||||
vm.selectFilter('userSelect');
|
||||
|
||||
expect(vm.selectedFilters.changedModelId).toEqual('1');
|
||||
expect(vm.selectedFilters.userFk).toEqual('21');
|
||||
expect(vm.selectedFilters.action).toEqual({ inq: ['insert', 'update'] });
|
||||
});
|
||||
|
||||
it('should correctly set the date from', () => {
|
||||
vm.dateFrom = '18-09-2023';
|
||||
vm.selectFilter('date', 'from');
|
||||
expect(vm.selectedFilters.creationDate.between).toEqual([
|
||||
new Date('2023-09-18T00:00:00.000Z'),
|
||||
new Date('2023-09-18T21:59:59.999Z'),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
|
||||
import { createWrapper } from 'app/test/vitest/helper';
|
||||
import VnLogFilter from 'src/components/common/VnLogFilter.vue';
|
||||
|
||||
describe('VnLogFilter', () => {
|
||||
let vm;
|
||||
beforeAll(async () => {
|
||||
vm = createWrapper(VnLogFilter, {
|
||||
props: {
|
||||
dataKey: 'ClaimLog',
|
||||
},
|
||||
}).vm;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should getActions selected', async () => {
|
||||
vm.checkboxOptions.find((o) => o.name == 'insert').selected = true;
|
||||
vm.checkboxOptions.find((o) => o.name == 'update').selected = true;
|
||||
|
||||
const actions = vm.getActions();
|
||||
|
||||
expect(actions.length).toEqual(2);
|
||||
expect(actions).toEqual(['insert', 'update']);
|
||||
});
|
||||
});
|
|
@ -61,6 +61,10 @@ const $props = defineProps({
|
|||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
showTagChips: {
|
||||
jorgep marked this conversation as resolved
alexm
commented
Añado esta propiedad, ya que en VnLogFilter no veo que valga la pena tenerlo, ademas hace que no vaya bien los checkboxs Añado esta propiedad, ya que en VnLogFilter no veo que valga la pena tenerlo, ademas hace que no vaya bien los checkboxs
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
|
@ -88,13 +92,14 @@ const userOrders = ref(useFilterParams($props.dataKey).orders);
|
|||
defineExpose({ search, params: userParams, remove });
|
||||
|
||||
const isLoading = ref(false);
|
||||
async function search(evt) {
|
||||
async function search(evt, name, value) {
|
||||
try {
|
||||
if (evt && $props.disableSubmitEvent) return;
|
||||
|
||||
store.filter.where = {};
|
||||
isLoading.value = true;
|
||||
const filter = { ...userParams.value, ...$props.modelValue };
|
||||
if (name) filter[name] = value;
|
||||
store.userParamsChanged = true;
|
||||
await arrayData.addFilter({
|
||||
params: filter,
|
||||
|
@ -214,7 +219,7 @@ const getLocale = (label) => {
|
|||
</QTooltip>
|
||||
</QBtn>
|
||||
<QForm @submit="search" id="filterPanelForm" @keyup.enter="search()">
|
||||
<QList dense>
|
||||
<QList dense v-if="showTagChips">
|
||||
<QItem class="q-mt-xs">
|
||||
<QItemSection top>
|
||||
<QItemLabel header lines="1" class="text-uppercase q-py-xs q-px-none">
|
||||
|
|
|
@ -215,6 +215,7 @@ defineExpose({
|
|||
paginate,
|
||||
userParams: arrayData.store.userParams,
|
||||
currentFilter: arrayData.store.currentFilter,
|
||||
arrayData,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@ export function useArrayData(key, userOptions) {
|
|||
|
||||
store.order = order;
|
||||
resetPagination();
|
||||
fetch({});
|
||||
await fetch({});
|
||||
jorgep marked this conversation as resolved
alexm
commented
Hacia que si falla la petición no se puede manejar Hacia que si falla la petición no se puede manejar
|
||||
index++;
|
||||
|
||||
return { index, order };
|
||||
|
|
|
@ -14,7 +14,7 @@ export function useFilterParams(key) {
|
|||
watch(
|
||||
() => arrayData.value.store?.currentFilter,
|
||||
(val, oldValue) => (val || oldValue) && setUserParams(val),
|
||||
{ immediate: true, deep: true }
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
function parseOrder(urlOrders) {
|
||||
|
@ -54,7 +54,7 @@ export function useFilterParams(key) {
|
|||
Object.assign(params, item);
|
||||
});
|
||||
delete params[key];
|
||||
} else if (value && typeof value === 'object') {
|
||||
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||
const param = Object.values(value)[0];
|
||||
if (typeof param == 'string') params[key] = param.replaceAll('%', '');
|
||||
}
|
||||
|
|
|
@ -370,6 +370,11 @@ globals:
|
|||
countryCodeFk: Country
|
||||
companyFk: Company
|
||||
nickname: Alias
|
||||
changedModel: Entity
|
||||
changedModelValue: Search
|
||||
changedModelId: Entity id
|
||||
userFk: User
|
||||
action: Action
|
||||
model: Model
|
||||
fuel: Fuel
|
||||
active: Active
|
||||
|
|
|
@ -371,6 +371,11 @@ globals:
|
|||
countryCodeFk: País
|
||||
companyFk: Empresa
|
||||
nickname: Alias
|
||||
changedModel: Entidad
|
||||
changedModelValue: Buscar
|
||||
changedModelId: Id de entidad
|
||||
userFk: Usuario
|
||||
action: Acción
|
||||
errors:
|
||||
statusUnauthorized: Acceso denegado
|
||||
statusInternalServerError: Ha ocurrido un error interno del servidor
|
||||
|
|
|
@ -213,7 +213,7 @@ function exprBuilder(param, value) {
|
|||
}"
|
||||
>
|
||||
<template #advanced-menu>
|
||||
<RoadmapFilter :dataKey />
|
||||
<RoadmapFilter :data-key />
|
||||
</template>
|
||||
<template #body>
|
||||
<VnTable
|
||||
|
|
|
@ -377,10 +377,12 @@ const newOrderFromTicket = async () => {
|
|||
const goToLog = (saleId) => {
|
||||
router.push({
|
||||
name: 'TicketLog',
|
||||
params: {
|
||||
originId: route.params.id,
|
||||
changedModel: 'Sale',
|
||||
changedModelId: saleId,
|
||||
query: {
|
||||
jorgep marked this conversation as resolved
alexm
commented
Arreglado 😉 Arreglado 😉
|
||||
logs: JSON.stringify({
|
||||
originFk: route.params.id,
|
||||
changedModel: 'Sale',
|
||||
changedModelId: saleId,
|
||||
}),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,26 +1,23 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('VnLog', () => {
|
||||
const chips = [
|
||||
':nth-child(1) > :nth-child(1) > .q-item__label > .q-chip > .q-chip__content',
|
||||
':nth-child(2) > :nth-child(1) > .q-item__label > .q-chip > .q-chip__content',
|
||||
];
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/claim/${1}/log`);
|
||||
cy.openRightMenu();
|
||||
});
|
||||
|
||||
it('should filter by insert actions', () => {
|
||||
cy.checkOption(':nth-child(7) > .q-checkbox');
|
||||
cy.get('.q-page').click();
|
||||
cy.validateContent(chips[0], 'Document');
|
||||
cy.validateContent(chips[1], 'Beginning');
|
||||
cy.get('[data-cy="vnLog-checkbox"]').eq(0).click();
|
||||
jorgep marked this conversation as resolved
alexm
commented
Los mejoro, basandome en resultados del VnLog, no en chips... Los mejoro, basandome en resultados del VnLog, no en chips...
|
||||
cy.get('[data-cy="vnLog-action-icon"]').each(($el) => {
|
||||
cy.wrap($el).should('have.attr', 'title', 'Creates');
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter by entity', () => {
|
||||
cy.selectOption('.q-drawer--right .q-item > .q-select', 'Claim');
|
||||
cy.get('.q-page').click();
|
||||
cy.validateContent(chips[0], 'Beginning');
|
||||
const entity = 'Document';
|
||||
cy.selectOption('[data-cy="vnLog-entity"]', entity);
|
||||
cy.get('[data-cy="vnLog-model-chip"]').each(($el) => {
|
||||
cy.wrap($el).should('have.text', entity);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show claimDescriptor', () => {
|
||||
|
|
Loading…
Reference in New Issue
El and estaba mal. ya que hace que no salga el modo sin ningún order