diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue
index 1040c6791..424781a26 100644
--- a/src/components/common/VnDmsList.vue
+++ b/src/components/common/VnDmsList.vue
@@ -17,7 +17,7 @@ import { useSession } from 'src/composables/useSession';
const route = useRoute();
const quasar = useQuasar();
const { t } = useI18n();
-const rows = ref();
+const rows = ref([]);
const dmsRef = ref();
const formDialog = ref({});
const token = useSession().getTokenMultimedia();
@@ -389,6 +389,14 @@ defineExpose({
+
+
+ {{ t('No data to display') }}
+
+
diff --git a/src/components/common/__tests__/VnNotes.spec.js b/src/components/common/__tests__/VnNotes.spec.js
index 8f24a7f14..2603bf03c 100644
--- a/src/components/common/__tests__/VnNotes.spec.js
+++ b/src/components/common/__tests__/VnNotes.spec.js
@@ -1,51 +1,78 @@
-import { describe, it, expect, vi, beforeAll, afterEach, beforeEach } from 'vitest';
+import {
+ describe,
+ it,
+ expect,
+ vi,
+ beforeAll,
+ afterEach,
+ beforeEach,
+ afterAll,
+} from 'vitest';
import { createWrapper, axios } from 'app/test/vitest/helper';
import VnNotes from 'src/components/ui/VnNotes.vue';
+import vnDate from 'src/boot/vnDate';
describe('VnNotes', () => {
let vm;
let wrapper;
let spyFetch;
let postMock;
- let expectedBody;
- const mockData= {name: 'Tony', lastName: 'Stark', text: 'Test Note', observationTypeFk: 1};
-
- function generateExpectedBody() {
- expectedBody = {...vm.$props.body, ...{ text: vm.newNote.text, observationTypeFk: vm.newNote.observationTypeFk }};
- }
-
- async function setTestParams(text, observationType, type){
- vm.newNote.text = text;
- vm.newNote.observationTypeFk = observationType;
- wrapper.setProps({ selectType: type });
- }
-
- beforeAll(async () => {
- vi.spyOn(axios, 'get').mockReturnValue({ data: [] });
-
+ let patchMock;
+ let expectedInsertBody;
+ let expectedUpdateBody;
+ const defaultOptions = {
+ url: '/test',
+ body: { name: 'Tony', lastName: 'Stark' },
+ selectType: false,
+ saveUrl: null,
+ justInput: false,
+ };
+ function generateWrapper(
+ options = defaultOptions,
+ text = null,
+ observationType = null,
+ ) {
+ vi.spyOn(axios, 'get').mockResolvedValue({ data: [] });
wrapper = createWrapper(VnNotes, {
- propsData: {
- url: '/test',
- body: { name: 'Tony', lastName: 'Stark' },
- }
+ propsData: options,
});
wrapper = wrapper.wrapper;
vm = wrapper.vm;
- });
+ vm.newNote.text = text;
+ vm.newNote.observationTypeFk = observationType;
+ }
+
+ function createSpyFetch() {
+ spyFetch = vi.spyOn(vm.$refs.vnPaginateRef, 'fetch');
+ }
+
+ function generateExpectedBody() {
+ expectedInsertBody = {
+ ...vm.$props.body,
+ ...{ text: vm.newNote.text, observationTypeFk: vm.newNote.observationTypeFk },
+ };
+ expectedUpdateBody = { ...vm.$props.body, ...{ notes: vm.newNote.text } };
+ }
beforeEach(() => {
- postMock = vi.spyOn(axios, 'post').mockResolvedValue(mockData);
- spyFetch = vi.spyOn(vm.vnPaginateRef, 'fetch').mockImplementation(() => vi.fn());
+ postMock = vi.spyOn(axios, 'post');
+ patchMock = vi.spyOn(axios, 'patch');
});
afterEach(() => {
vi.clearAllMocks();
- expectedBody = {};
+ expectedInsertBody = {};
+ expectedUpdateBody = {};
+ });
+
+ afterAll(() => {
+ vi.restoreAllMocks();
});
describe('insert', () => {
- it('should not call axios.post and vnPaginateRef.fetch if newNote.text is null', async () => {
- await setTestParams( null, null, true );
+ it('should not call axios.post and vnPaginateRef.fetch when newNote.text is null', async () => {
+ generateWrapper({ selectType: true });
+ createSpyFetch();
await vm.insert();
@@ -53,8 +80,9 @@ describe('VnNotes', () => {
expect(spyFetch).not.toHaveBeenCalled();
});
- it('should not call axios.post and vnPaginateRef.fetch if newNote.text is empty', async () => {
- await setTestParams( "", null, false );
+ it('should not call axios.post and vnPaginateRef.fetch when newNote.text is empty', async () => {
+ generateWrapper(null, '');
+ createSpyFetch();
await vm.insert();
@@ -62,8 +90,9 @@ describe('VnNotes', () => {
expect(spyFetch).not.toHaveBeenCalled();
});
- it('should not call axios.post and vnPaginateRef.fetch if observationTypeFk is missing and selectType is true', async () => {
- await setTestParams( "Test Note", null, true );
+ it('should not call axios.post and vnPaginateRef.fetch when observationTypeFk is null and selectType is true', async () => {
+ generateWrapper({ selectType: true }, 'Test Note');
+ createSpyFetch();
await vm.insert();
@@ -71,37 +100,57 @@ describe('VnNotes', () => {
expect(spyFetch).not.toHaveBeenCalled();
});
- it('should call axios.post and vnPaginateRef.fetch if observationTypeFk is missing and selectType is false', async () => {
- await setTestParams( "Test Note", null, false );
-
+ it('should call axios.post and vnPaginateRef.fetch when observationTypeFk is missing and selectType is false', async () => {
+ generateWrapper(null, 'Test Note');
+ createSpyFetch();
generateExpectedBody();
await vm.insert();
- expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedBody);
- expect(spyFetch).toHaveBeenCalled();
- });
-
- it('should call axios.post and vnPaginateRef.fetch if observationTypeFk is setted and selectType is false', async () => {
- await setTestParams( "Test Note", 1, false );
-
- generateExpectedBody();
-
- await vm.insert();
-
- expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedBody);
+ expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedInsertBody);
expect(spyFetch).toHaveBeenCalled();
});
it('should call axios.post and vnPaginateRef.fetch when newNote is valid', async () => {
- await setTestParams( "Test Note", 1, true );
-
+ generateWrapper({ selectType: true }, 'Test Note', 1);
+ createSpyFetch();
generateExpectedBody();
-
+
await vm.insert();
- expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedBody);
+ expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedInsertBody);
expect(spyFetch).toHaveBeenCalled();
});
});
-});
\ No newline at end of file
+
+ describe('update', () => {
+ it('should call axios.patch with saveUrl when saveUrl is set and justInput is true', async () => {
+ generateWrapper({
+ url: '/business',
+ justInput: true,
+ saveUrl: '/saveUrlTest',
+ });
+ generateExpectedBody();
+
+ await vm.update();
+
+ expect(patchMock).toHaveBeenCalledWith(vm.$props.saveUrl, expectedUpdateBody);
+ });
+
+ it('should call axios.patch with url when saveUrl is not set and justInput is true', async () => {
+ generateWrapper({
+ url: '/business',
+ body: { workerFk: 1110 },
+ justInput: true,
+ });
+ generateExpectedBody();
+
+ await vm.update();
+
+ expect(patchMock).toHaveBeenCalledWith(
+ `${vm.$props.url}/${vm.$props.body.workerFk}`,
+ expectedUpdateBody,
+ );
+ });
+ });
+});
diff --git a/src/components/ui/VnNotes.vue b/src/components/ui/VnNotes.vue
index 1690a94ba..5b1d6e726 100644
--- a/src/components/ui/VnNotes.vue
+++ b/src/components/ui/VnNotes.vue
@@ -1,6 +1,6 @@
{
auto-load
@on-fetch="(data) => (observationTypes = data)"
/>
-
-
+
+
+
{{ t('New note') }}
@@ -75,19 +138,19 @@ onBeforeRouteLeave((to, from, next) => {
v-model="newNote.observationTypeFk"
option-label="description"
style="flex: 0.15"
- :required="true"
+ :required="isRequired"
@keyup.enter.stop="insert"
/>
{
icon="save"
color="primary"
flat
- @click="insert"
+ @click="handleClick"
class="q-mb-xs"
dense
data-cy="saveNote"
@@ -106,6 +169,7 @@ onBeforeRouteLeave((to, from, next) => {
{
}
}
}
+.just-input {
+ padding-right: 18px;
+ margin-bottom: 2px;
+ box-shadow: none;
+}
es:
@@ -205,4 +274,6 @@ onBeforeRouteLeave((to, from, next) => {
New note: Nueva nota
Save (Enter): Guardar (Intro)
Observation type: Tipo de observación
+ New note is empty: La nueva nota esta vacia
+ Are you sure remove this note?: Estas seguro de quitar esta nota?
diff --git a/src/components/ui/VnSubToolbar.vue b/src/components/ui/VnSubToolbar.vue
index 5ded4be00..8d4126d1d 100644
--- a/src/components/ui/VnSubToolbar.vue
+++ b/src/components/ui/VnSubToolbar.vue
@@ -19,23 +19,26 @@ onMounted(() => {
const observer = new MutationObserver(
() =>
(hasContent.value =
- actions.value?.childNodes?.length + data.value?.childNodes?.length)
+ actions.value?.childNodes?.length + data.value?.childNodes?.length),
);
if (actions.value) observer.observe(actions.value, opts);
if (data.value) observer.observe(data.value, opts);
});
-onBeforeUnmount(() => stateStore.toggleSubToolbar());
+const actionsChildCount = () => !!actions.value?.childNodes?.length;
+
+onBeforeUnmount(() => stateStore.toggleSubToolbar() && hasSubToolbar);
-
+
+
diff --git a/src/pages/Customer/Card/CustomerNotes.vue b/src/pages/Customer/Card/CustomerNotes.vue
index b85174696..189b59904 100644
--- a/src/pages/Customer/Card/CustomerNotes.vue
+++ b/src/pages/Customer/Card/CustomerNotes.vue
@@ -23,5 +23,6 @@ const noteFilter = computed(() => {
:body="{ clientFk: route.params.id }"
style="overflow-y: auto"
:select-type="true"
+ required
/>
diff --git a/src/pages/Monitor/Ticket/MonitorTickets.vue b/src/pages/Monitor/Ticket/MonitorTickets.vue
index e6b4631a0..3b5dccb56 100644
--- a/src/pages/Monitor/Ticket/MonitorTickets.vue
+++ b/src/pages/Monitor/Ticket/MonitorTickets.vue
@@ -293,7 +293,7 @@ const columns = computed(() => [
title: t('globals.preview'),
icon: 'preview',
color: 'primary',
- action: (row) => viewSummary(row.id, TicketSummary),
+ action: (row) => viewSummary(row.id, TicketSummary, 'lg-width'),
isPrimary: true,
attrs: {
flat: true,
diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue
index 151bea97a..a662ef0c2 100644
--- a/src/pages/Ticket/Card/TicketSummary.vue
+++ b/src/pages/Ticket/Card/TicketSummary.vue
@@ -244,7 +244,7 @@ onMounted(async () => {
-import { nextTick, ref, watch } from 'vue';
+import { nextTick, ref, watch, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
+import { useAcl } from 'src/composables/useAcl';
import WorkerCalendarFilter from 'pages/Worker/Card/WorkerCalendarFilter.vue';
import FetchData from 'components/FetchData.vue';
@@ -9,10 +10,17 @@ import WorkerCalendarItem from 'pages/Worker/Card/WorkerCalendarItem.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import axios from 'axios';
+import VnNotes from 'src/components/ui/VnNotes.vue';
+import { useStateStore } from 'src/stores/useStateStore';
+const stateStore = useStateStore();
const router = useRouter();
const route = useRoute();
const { t } = useI18n();
+const acl = useAcl();
+const canSeeNotes = computed(() =>
+ acl.hasAny([{ model: 'Worker', props: '__get__business', accessType: 'READ' }]),
+);
const workerIsFreelance = ref();
const WorkerFreelanceRef = ref();
const workerCalendarFilterRef = ref(null);
@@ -26,6 +34,10 @@ const contractHolidays = ref(null);
const yearHolidays = ref(null);
const eventsMap = ref({});
const festiveEventsMap = ref({});
+const saveUrl = ref();
+const body = {
+ workerFk: route.params.id,
+};
const onFetchActiveContract = (data) => {
if (!data) return;
@@ -67,7 +79,7 @@ const onFetchAbsences = (data) => {
name: holidayName,
isFestive: true,
},
- true
+ true,
);
});
}
@@ -146,7 +158,7 @@ watch(
async () => {
await nextTick();
await activeContractRef.value.fetch();
- }
+ },
);
watch([year, businessFk], () => refreshData());
@@ -181,6 +193,20 @@ watch([year, businessFk], () => refreshData());
/>
+
+ {
+ saveUrl = `Businesses/${data.id}`;
+ }
+ "
+ :body="body"
+ />
+
diff --git a/src/pages/Worker/Card/WorkerCalendarFilter.vue b/src/pages/Worker/Card/WorkerCalendarFilter.vue
index 67b7df907..48fc4094b 100644
--- a/src/pages/Worker/Card/WorkerCalendarFilter.vue
+++ b/src/pages/Worker/Card/WorkerCalendarFilter.vue
@@ -180,8 +180,6 @@ const yearList = ref(generateYears());
:is-clearable="false"
/>
-
-
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
-import { ref, computed } from 'vue';
+import { ref, computed, watch } from 'vue';
import FetchData from 'components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
@@ -19,6 +19,7 @@ const trainsData = ref([]);
const machinesData = ref([]);
const route = useRoute();
const routeId = computed(() => route.params.id);
+const selected = ref([]);
const initialData = computed(() => {
return {
@@ -41,6 +42,21 @@ async function insert() {
await axios.post('Operators', initialData.value);
crudModelRef.value.reload();
}
+
+watch(
+ () => crudModelRef.value?.formData,
+ (formData) => {
+ if (formData && formData.length) {
+ if (JSON.stringify(selected.value) !== JSON.stringify(formData)) {
+ selected.value = formData;
+ }
+ } else if (selected.value.length > 0) {
+ selected.value = [];
+ }
+ },
+ { immediate: true, deep: true }
+);
+
@@ -67,6 +83,7 @@ async function insert() {
:data-required="{ workerFk: route.params.id }"
ref="crudModelRef"
search-url="operator"
+ :selected="selected"
auto-load
>