-
+
{{ t('globals.collapseMenu') }}
@@ -131,28 +644,414 @@ function actionColor(action) {
-
+
+
+
+ selectFilter('search')"
+ @focusout="() => selectFilter('search')"
+ @clear="() => selectFilter('search')"
+ >
+
+
+ {{ t('tooltips.search') }}
+
+
+
+
+
+
+ filterFn(val, update, abortFn, 'actions')
+ "
+ @clear="() => selectFilter('action')"
+ >
+
+
+ {{ t(`models.${opt}`) }}
+
+
+
+ {{ t(opt) }}
+
+
+
+
+
+
+ {{ t(`Users.${label}`) }}
+
+
+
+
+
+
+
+
+
+ filterFn(val, update, abortFn, 'workers')
+ "
+ >
+
+
+
+
+
+
+ {{ opt.name }}
+ {{ opt.nickname }}
+
+
+
+
+
+
+
+
+
+
+ {{
+ t('tooltips.changes')
+ }}
+
+
+
+
+
+
+
+
+ evt.target.blur()"
+ @clear="selectFilter('date', 'to')"
+ v-model="date"
+ clearable
+ clear-icon="close"
+ />
+
+
+ evt.target.blur()"
+ @clear="selectFilter('date', 'from')"
+ v-model="dateTo"
+ clearable
+ clear-icon="close"
+ />
+
+
+
+ {
+ dateDialog = false;
+ const formatDate = toDateString(new Date(value));
+ date = formatDate.split('-').reverse().join('-');
+ selectFilter('date', 'from');
+ }
+ "
+ />
+
+
+ {
+ dateToDialog = false;
+ const formatDate = toDateString(new Date(value));
+ dateTo = formatDate.split('-').reverse().join('-');
+ selectFilter('date', 'to');
+ }
+ "
+ />
+
+
+
+
-
+
en:
+ to: To
+ pointRecord: View record at this point in time
+ recordChanges: show all record changes
+ tooltips:
+ search: Search by id or concept
+ changes: Search by changes
actions:
- insert: Creates
- update: Updates
- delete: Deletes
+ Creates: Creates
+ Edits: Edits
+ Deletes: Deletes
+ Accesses: Accesses
models:
- Claim: Claim
- ClaimDms: Document
- ClaimBeginning: Claimed Sales
- ClaimObservation: Observation
+ Claim: Reclamación
+ ClaimDms: Documento
+ ClaimBeginning: Comienzo
+ ClaimObservation: Observación
+ Users:
+ User: Usuario
+ All: Todo
+ System: Sistema
properties:
id: ID
claimFk: Claim ID
@@ -172,6 +1071,12 @@ en:
responsibility: Responsibility
packages: Packages
es:
+ to: Hasta
+ pointRecord: Ver el registro en este punto
+ recordChanges: Mostrar todos los cambios realizados en el registro
+ 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.
Audit logs: Registros de auditoría
Property: Propiedad
Before: Antes
@@ -179,14 +1084,14 @@ es:
Yes: Si
Nothing: Nada
actions:
- insert: Crea
- update: Actualiza
- delete: Elimina
- models:
- Claim: Reclamación
- ClaimDms: Documento
- ClaimBeginning: Línea reclamada
- ClaimObservation: Observación
+ Creates: Crea
+ Edits: Modifica
+ Deletes: Elimina
+ Accesses: Accede
+ Users:
+ User: Usuario
+ All: Todo
+ System: Sistema
properties:
id: ID
claimFk: ID reclamación
diff --git a/src/composables/useColor.js b/src/composables/useColor.js
new file mode 100644
index 0000000000..b325e985f1
--- /dev/null
+++ b/src/composables/useColor.js
@@ -0,0 +1,35 @@
+export function djb2a(string) {
+ let hash = 5381;
+ for (let i = 0; i < string.length; i++)
+ hash = ((hash << 5) + hash) ^ string.charCodeAt(i);
+ return hash >>> 0;
+}
+
+export function useColor(value) {
+ return '#' + colors[djb2a(value || '') % colors.length];
+}
+
+const colors = [
+ 'b5b941', // Yellow
+ 'ae9681', // Peach
+ 'd78767', // Salmon
+ 'cc7000', // Orange bright
+ 'e2553d', // Coral
+ '8B0000', // Red dark
+ 'de4362', // Red crimson
+ 'FF1493', // Ping intense
+ 'be39a2', // Pink light
+ 'b754cf', // Purple middle
+ 'a87ba8', // Pink
+ '8a69cd', // Blue lavender
+ 'ab20ab', // Purple dark
+ '00b5b8', // Turquoise
+ '1fa8a1', // Green ocean
+ '5681cf', // Blue steel
+ '3399fe', // Blue sky
+ '6d9c3e', // Green chartreuse
+ '51bb51', // Green lime
+ '518b8b', // Gray board
+ '7e7e7e', // Gray
+ '5d5d5d', // Gray dark
+];
diff --git a/src/composables/useFirstUpper.js b/src/composables/useFirstUpper.js
new file mode 100644
index 0000000000..36378c05fc
--- /dev/null
+++ b/src/composables/useFirstUpper.js
@@ -0,0 +1,3 @@
+export function useFirstUpper(str) {
+ return str && str.charAt(0).toUpperCase() + str.substr(1);
+}
diff --git a/src/composables/useIso8601.js b/src/composables/useIso8601.js
new file mode 100644
index 0000000000..848e60de83
--- /dev/null
+++ b/src/composables/useIso8601.js
@@ -0,0 +1,18 @@
+export function useIso8601(dateString) {
+ // Crear un objeto Date a partir de la cadena de texto
+ const date = new Date(dateString);
+
+ // Obtener los componentes de fecha y hora
+ const year = date.getUTCFullYear();
+ const month = String(date.getUTCMonth() + 1).padStart(2, '0');
+ const day = String(date.getUTCDate()).padStart(2, '0');
+ const hours = String(date.getUTCHours()).padStart(2, '0');
+ const minutes = String(date.getUTCMinutes()).padStart(2, '0');
+ const seconds = String(date.getUTCSeconds()).padStart(2, '0');
+ const milliseconds = String(date.getUTCMilliseconds()).padStart(3, '0');
+
+ // Formatear la cadena en el formato ISO 8601
+ const formattedDate = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}Z`;
+
+ return formattedDate;
+}
diff --git a/src/css/app.scss b/src/css/app.scss
index 3c8cc50b64..9ed51c1c72 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -14,6 +14,10 @@ a {
color: $orange-4;
}
+.rounded--full {
+ border-radius: 50%;
+}
+
// Removes chrome autofill background
input:-webkit-autofill,
select:-webkit-autofill {
@@ -32,10 +36,12 @@ body.body--light {
--vn-text: #000000;
--vn-gray: #f5f5f5;
--vn-label: #5f5f5f;
+ --vn-header: #e9e9e9;
}
body.body--dark {
--vn-text: #ffffff;
--vn-gray: #313131;
--vn-label: #a8a8a8;
+ --vn-header: #212121;
}
diff --git a/src/filters/index.js b/src/filters/index.js
index 158ce1009b..b0c441641c 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -2,6 +2,7 @@ import toLowerCase from './toLowerCase';
import toDate from './toDate';
import toDateString from './toDateString';
import toDateHour from './toDateHour';
+import toRelativeDate from './toRelativeDate';
import toCurrency from './toCurrency';
import toPercentage from './toPercentage';
import toLowerCamel from './toLowerCamel';
@@ -13,6 +14,7 @@ export {
toDate,
toDateString,
toDateHour,
+ toRelativeDate,
toCurrency,
toPercentage,
dashIfEmpty,
diff --git a/src/filters/toRelativeDate.js b/src/filters/toRelativeDate.js
new file mode 100644
index 0000000000..76e67dbeae
--- /dev/null
+++ b/src/filters/toRelativeDate.js
@@ -0,0 +1,32 @@
+import { useI18n } from 'vue-i18n';
+
+export default function formatDate(dateVal) {
+ const { t } = useI18n();
+ const today = new Date();
+ if (dateVal == null) return '';
+
+ const date = new Date(dateVal);
+ const dateZeroTime = new Date(dateVal);
+ dateZeroTime.setHours(0, 0, 0, 0);
+ const diff = Math.trunc(
+ (today.getTime() - dateZeroTime.getTime()) / (1000 * 3600 * 24)
+ );
+ let format;
+ if (diff === 0) format = t('globals.today');
+ else if (diff === 1) format = t('globals.yesterday');
+ else if (diff > 1 && diff < 7) {
+ const options = { weekday: 'short' };
+ format = date.toLocaleDateString(t('globals.dateFormat'), options);
+ } else if (today.getFullYear() === date.getFullYear()) {
+ const options = { day: 'numeric', month: 'short' };
+ format = date.toLocaleDateString(t('globals.dateFormat'), options);
+ } else {
+ const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
+ format = date.toLocaleDateString(t('globals.dateFormat'), options);
+ }
+
+ // Formatear la hora en HH:mm
+ const hours = date.getHours().toString().padStart(2, '0');
+ const minutes = date.getMinutes().toString().padStart(2, '0');
+ return `${format} ${hours}:${minutes}`;
+}
diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js
index d7519ba533..285fb778f9 100644
--- a/src/i18n/en/index.js
+++ b/src/i18n/en/index.js
@@ -5,6 +5,9 @@ export default {
en: 'English',
},
language: 'Language',
+ entity: 'Entity',
+ user: 'User',
+ details: 'Details',
collapseMenu: 'Collapse left menu',
backToDashboard: 'Return to dashboard',
notifications: 'Notifications',
@@ -13,8 +16,11 @@ export default {
pinnedModules: 'Pinned modules',
darkMode: 'Dark mode',
logOut: 'Log out',
+ date: 'Date',
dataSaved: 'Data saved',
dataDeleted: 'Data deleted',
+ search: 'Search',
+ changes: 'Changes',
add: 'Add',
create: 'Create',
save: 'Save',
@@ -36,6 +42,9 @@ export default {
summary: {
basicData: 'Basic data',
},
+ today: 'Today',
+ yesterday: 'Yesterday',
+ dateFormat: 'en-GB',
},
errors: {
statusUnauthorized: 'Access denied',
diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js
index fc2c80f551..97001eab85 100644
--- a/src/i18n/es/index.js
+++ b/src/i18n/es/index.js
@@ -5,6 +5,9 @@ export default {
en: 'Inglés',
},
language: 'Idioma',
+ entity: 'Entidad',
+ user: 'Usuario',
+ details: 'Detalles',
collapseMenu: 'Contraer menú lateral',
backToDashboard: 'Volver al tablón',
notifications: 'Notificaciones',
@@ -13,8 +16,11 @@ export default {
pinnedModules: 'Módulos fijados',
darkMode: 'Modo oscuro',
logOut: 'Cerrar sesión',
+ date: 'Fecha',
dataSaved: 'Datos guardados',
dataDeleted: 'Datos eliminados',
+ search: 'Buscar',
+ changes: 'Cambios',
add: 'Añadir',
create: 'Crear',
save: 'Guardar',
@@ -36,6 +42,9 @@ export default {
summary: {
basicData: 'Datos básicos',
},
+ today: 'Hoy',
+ yesterday: 'Ayer',
+ dateFormat: 'es-ES',
},
errors: {
statusUnauthorized: 'Acceso denegado',
diff --git a/src/stores/useValidationsStore.js b/src/stores/useValidationsStore.js
new file mode 100644
index 0000000000..c658a90af4
--- /dev/null
+++ b/src/stores/useValidationsStore.js
@@ -0,0 +1,19 @@
+import axios from 'axios';
+import { defineStore } from 'pinia';
+
+export const useValidationsStore = defineStore('validationsStore', {
+ state: () => ({
+ validations: null,
+ }),
+ actions: {
+ async fetchModels() {
+ if (this.validations) return;
+ try {
+ const { data } = await axios.get('Schemas/modelinfo');
+ this.validations = data;
+ } catch (error) {
+ console.error('Error al obtener las validaciones:', error);
+ }
+ },
+ },
+});
diff --git a/test/cypress/integration/ClaimNotes.spec.js b/test/cypress/integration/ClaimNotes.spec.js
index 5b52dd3398..9f52c29e4b 100644
--- a/test/cypress/integration/ClaimNotes.spec.js
+++ b/test/cypress/integration/ClaimNotes.spec.js
@@ -8,6 +8,7 @@ describe('ClaimNotes', () => {
it('should add a new note', () => {
const message = 'This is a new message.';
cy.get('.q-page-sticky button').click();
+ cy.get('.q-page-sticky > div > button').click();
cy.get('.q-dialog .q-card__section:nth-child(2)').type(message);
cy.get('.q-card__actions button:nth-child(2)').click();
cy.get('.q-card .q-card__section:nth-child(2)')
diff --git a/test/cypress/integration/vnLog.spec.js b/test/cypress/integration/vnLog.spec.js
new file mode 100644
index 0000000000..3d6d9b95de
--- /dev/null
+++ b/test/cypress/integration/vnLog.spec.js
@@ -0,0 +1,31 @@
+///
+describe('ClaimNotes', () => {
+ beforeEach(() => {
+ cy.login('developer');
+ cy.visit(`/#/claim/${1}/log`);
+ });
+
+ it('should have just one record', () => {
+ cy.get('.model-info .q-btn').eq(1).click();
+ cy.get('.user-log .model-log').its('length').should('eq', 1);
+ cy.get('.q-page-sticky .q-btn').click();
+ cy.get('.user-log .model-log').its('length').should('eq', 4);
+ });
+
+ it('should filter by insert actions', () => {
+ cy.get('.q-gutter-x-sm > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get('.q-checkbox__inner').eq(0).click();
+ cy.get('.q-page > .q-drawer-container > .fullscreen').click();
+ cy.get('.model-info .q-chip__content').eq(0).should('have.text', 'Document');
+ cy.get('.model-info .q-chip__content').eq(1).should('have.text', 'Beginning');
+ });
+
+ it('should show the point record', () => {
+ cy.get('.pit').eq(0).click();
+ cy.get('.q-menu .q-card .header').should('have.text', 'Observation #1');
+ cy.get('.q-menu .q-card .json-string').should(
+ 'have.text',
+ 'Waiting for customer'
+ );
+ });
+});
diff --git a/test/cypress/integration/workerList.spec.js b/test/cypress/integration/workerList.spec.js
index d76958367a..8d4dd770d9 100644
--- a/test/cypress/integration/workerList.spec.js
+++ b/test/cypress/integration/workerList.spec.js
@@ -8,17 +8,17 @@ describe('WorkerList', () => {
it('should load workers', () => {
cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
.eq(0)
- .should('have.text', 'victorvd');
- cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
- .eq(1)
.should('have.text', 'JessicaJones');
cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
- .eq(2)
+ .eq(1)
.should('have.text', 'BruceBanner');
+ cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
+ .eq(2)
+ .should('have.text', 'CharlesXavier');
});
it('should open the worker summary', () => {
- cy.get('.card-list-body .actions .q-btn:nth-child(2)').eq(1).click();
+ cy.get('.card-list-body .actions .q-btn:nth-child(2)').eq(0).click();
cy.get('.summaryHeader div').should('have.text', '1110 - Jessica Jones');
cy.get('.summary .header').eq(0).invoke('text').should('include', 'Basic data');
cy.get('.summary .header').eq(1).should('have.text', 'User data');