refactor: refs #8684 enhance editability checks in VnTable and improve item request handling
gitea/salix-front/pipeline/pr-dev This commit is unstable Details

This commit is contained in:
Pablo Natek 2025-05-05 08:54:38 +02:00
parent ab6dc5d2ca
commit 240b927a02
4 changed files with 65 additions and 25 deletions

View File

@ -373,16 +373,20 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
}
}
function isEditableColumn(column) {
const isEditableCol = column?.isEditable ?? true;
function isEditableColumn(column, row) {
const isEditableCol =
typeof column?.isEditable == 'function'
? column?.isEditable(row)
: (column?.isEditable ?? true);
const isVisible = column?.visible ?? true;
const hasComponent = column?.component;
return $props.isEditable && isVisible && hasComponent && isEditableCol;
}
function hasEditableFormat(column) {
if (isEditableColumn(column)) return 'editable-text';
function hasEditableFormat(column, row) {
if (isEditableColumn(column, row)) return 'editable-text';
}
const clickHandler = async (event) => {
@ -394,6 +398,7 @@ const clickHandler = async (event) => {
if (isDateElement || isTimeElement || isQSelectDropDown) return;
if (clickedElement === null) {
console.log('destroyInput 1');
await destroyInput(editingRow.value, editingField.value);
return;
}
@ -404,17 +409,25 @@ const clickHandler = async (event) => {
if (editingRow.value !== null && editingField.value !== null) {
if (editingRow.value == rowIndex && editingField.value == colField) return;
console.log('destroyInput 2');
await destroyInput(editingRow.value, editingField.value);
}
if (isEditableColumn(column)) {
if (
isEditableColumn(
column,
CrudModelRef.value.formData[rowIndex ?? editingRow.value],
)
) {
await renderInput(Number(rowIndex), colField, clickedElement);
}
};
async function handleTabKey(event, rowIndex, colField) {
if (editingRow.value == rowIndex && editingField.value == colField)
if (editingRow.value == rowIndex && editingField.value == colField) {
console.log('destroyInput 3');
await destroyInput(editingRow.value, editingField.value);
}
const direction = event.shiftKey ? -1 : 1;
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
@ -426,6 +439,7 @@ async function handleTabKey(event, rowIndex, colField) {
if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;
event.preventDefault();
console.log('nextColumnName: ', nextColumnName);
await renderInput(nextRowIndex, nextColumnName, null);
}
@ -467,16 +481,21 @@ async function renderInput(rowId, field, clickedElement) {
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
},
keyup: async (event) => {
if (event.key === 'Enter')
if (event.key === 'Enter') {
console.log('destroyInput 4');
await destroyInput(rowId, field, clickedElement);
}
},
keydown: async (event) => {
switch (event.key) {
case 'Tab':
console.log('field: ', field);
console.log('target: ', event.target);
await handleTabKey(event, rowId, field);
event.stopPropagation();
break;
case 'Escape':
console.log('destroyInput 5');
await destroyInput(rowId, field, clickedElement);
break;
default:
@ -511,6 +530,10 @@ async function updateSelectValue(value, column, row, oldValue) {
}
async function destroyInput(rowIndex, field, clickedElement) {
const column = $props.columns.find((col) => col.name === field);
if (typeof column?.beforeDestroy === 'function')
await column.beforeDestroy(CrudModelRef.value.formData[rowIndex]);
if (!clickedElement)
clickedElement = document.querySelector(
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
@ -523,6 +546,7 @@ async function destroyInput(rowIndex, field, clickedElement) {
child.style.position = '';
});
}
if (editingRow.value !== rowIndex || editingField.value !== field) return;
editingRow.value = null;
editingField.value = null;
@ -540,7 +564,13 @@ async function handleTabNavigation(rowIndex, colName, direction) {
iterations++;
newColumnIndex = (newColumnIndex + direction + totalColumns) % totalColumns;
if (isEditableColumn(columns[newColumnIndex])) break;
if (
isEditableColumn(
columns[newColumnIndex],
CrudModelRef.value.formData[rowIndex],
)
)
break;
} while (iterations < totalColumns);
if (iterations >= totalColumns + 1) return;
@ -840,19 +870,19 @@ const handleHeaderSelection = (evt, data) => {
: getToggleIcon(row[col?.name])
"
style="color: var(--vn-text-color)"
:class="hasEditableFormat(col)"
:class="hasEditableFormat(col, row)"
size="14px"
/>
<QIcon
v-else-if="col?.component === 'checkbox'"
:name="getCheckboxIcon(row[col?.name])"
style="color: var(--vn-text-color)"
:class="hasEditableFormat(col)"
:class="hasEditableFormat(col, row)"
size="14px"
/>
<span
v-else
:class="hasEditableFormat(col)"
:class="hasEditableFormat(col, row)"
:style="
typeof col?.style == 'function'
? col.style(row)

View File

@ -13,7 +13,6 @@ import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/Departme
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import ItemRequestFilter from './ItemRequestFilter.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import FormModelPopup from 'src/components/FormModelPopup.vue';
import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
import { dashIfEmpty } from 'src/filters';
@ -23,8 +22,6 @@ const { notify } = useNotify();
const stateStore = useStateStore();
const denyFormRef = ref(null);
const denyRequestId = ref(null);
const denyRequestIndex = ref(null);
const itemRequestsOptions = ref([]);
const userParams = {
state: 'pending',
daysOnward: 7,
@ -146,7 +143,24 @@ const columns = computed(() => [
align: 'left',
component: 'input',
columnClass: 'shrink',
cellEvent: {},
isEditable: (row) => row?.itemFk,
beforeDestroy: async ({ id, itemFk, saleQuantity, state }) => {
if (!saleQuantity) {
await tableRef.value.reload();
return;
}
try {
await axios.post(`TicketRequests/${id}/confirm`, {
id,
itemFk: parseInt(itemFk),
quantity: parseInt(saleQuantity),
});
await tableRef.value.reload();
} catch (error) {
notify(error.response.data.error.message, 'negative');
console.log('error: ', error);
}
},
},
{
label: t('item.buyRequest.concept'),

View File

@ -6,8 +6,7 @@ describe('Item summary', () => {
});
it('should clone the item', () => {
cy.dataCy('descriptor-more-opts').click();
cy.get('.q-menu > .q-list > :nth-child(2) > .q-item__section').click();
cy.selectDescriptorOption(2);
cy.dataCy('VnConfirm_confirm').click();
cy.waitForElement('[data-cy="itemTags"]');
cy.dataCy('itemTags').should('be.visible');

View File

@ -1,15 +1,14 @@
describe('Item list', () => {
beforeEach(() => {
cy.login('developer');
cy.login('buyer');
cy.visit(`/#/item/list`);
});
it('should filter the items and redirect to the summary', () => {
cy.dataCy('Category_select').type('Plant');
cy.get('.q-menu .q-item').contains('Plant').click();
cy.dataCy('Type_select').type('Anthurium');
cy.get('.q-menu .q-item').contains('Anthurium').click();
cy.selectOption('[data-cy="Category_select"]', 'Plant');
cy.selectOption('[data-cy="Type_select"]', 'Anthurium');
cy.get('.q-virtual-scroll__content > :nth-child(4) > :nth-child(4)').click();
cy.url().should('include', '/summary');
});
it('should create an item', () => {
@ -24,8 +23,6 @@ describe('Item list', () => {
cy.fillInForm(data);
cy.dataCy('FormModelPopup_save').click();
cy.checkNotification('Data created');
cy.get(
':nth-child(2) > .q-drawer > .q-drawer__content > .q-scrollarea > .q-scrollarea__container > .q-scrollarea__content',
).should('be.visible');
cy.url().should('include', '/basic-data');
});
});