refactor: refs #8684 enhance editability checks in VnTable and improve item request handling
gitea/salix-front/pipeline/pr-dev This commit is unstable
Details
gitea/salix-front/pipeline/pr-dev This commit is unstable
Details
This commit is contained in:
parent
ab6dc5d2ca
commit
240b927a02
|
@ -373,16 +373,20 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEditableColumn(column) {
|
function isEditableColumn(column, row) {
|
||||||
const isEditableCol = column?.isEditable ?? true;
|
const isEditableCol =
|
||||||
|
typeof column?.isEditable == 'function'
|
||||||
|
? column?.isEditable(row)
|
||||||
|
: (column?.isEditable ?? true);
|
||||||
|
|
||||||
const isVisible = column?.visible ?? true;
|
const isVisible = column?.visible ?? true;
|
||||||
const hasComponent = column?.component;
|
const hasComponent = column?.component;
|
||||||
|
|
||||||
return $props.isEditable && isVisible && hasComponent && isEditableCol;
|
return $props.isEditable && isVisible && hasComponent && isEditableCol;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasEditableFormat(column) {
|
function hasEditableFormat(column, row) {
|
||||||
if (isEditableColumn(column)) return 'editable-text';
|
if (isEditableColumn(column, row)) return 'editable-text';
|
||||||
}
|
}
|
||||||
|
|
||||||
const clickHandler = async (event) => {
|
const clickHandler = async (event) => {
|
||||||
|
@ -394,6 +398,7 @@ const clickHandler = async (event) => {
|
||||||
if (isDateElement || isTimeElement || isQSelectDropDown) return;
|
if (isDateElement || isTimeElement || isQSelectDropDown) return;
|
||||||
|
|
||||||
if (clickedElement === null) {
|
if (clickedElement === null) {
|
||||||
|
console.log('destroyInput 1');
|
||||||
await destroyInput(editingRow.value, editingField.value);
|
await destroyInput(editingRow.value, editingField.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -404,17 +409,25 @@ const clickHandler = async (event) => {
|
||||||
if (editingRow.value !== null && editingField.value !== null) {
|
if (editingRow.value !== null && editingField.value !== null) {
|
||||||
if (editingRow.value == rowIndex && editingField.value == colField) return;
|
if (editingRow.value == rowIndex && editingField.value == colField) return;
|
||||||
|
|
||||||
|
console.log('destroyInput 2');
|
||||||
await destroyInput(editingRow.value, editingField.value);
|
await destroyInput(editingRow.value, editingField.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEditableColumn(column)) {
|
if (
|
||||||
|
isEditableColumn(
|
||||||
|
column,
|
||||||
|
CrudModelRef.value.formData[rowIndex ?? editingRow.value],
|
||||||
|
)
|
||||||
|
) {
|
||||||
await renderInput(Number(rowIndex), colField, clickedElement);
|
await renderInput(Number(rowIndex), colField, clickedElement);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleTabKey(event, rowIndex, colField) {
|
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);
|
await destroyInput(editingRow.value, editingField.value);
|
||||||
|
}
|
||||||
|
|
||||||
const direction = event.shiftKey ? -1 : 1;
|
const direction = event.shiftKey ? -1 : 1;
|
||||||
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
|
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
|
||||||
|
@ -426,6 +439,7 @@ async function handleTabKey(event, rowIndex, colField) {
|
||||||
if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;
|
if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
console.log('nextColumnName: ', nextColumnName);
|
||||||
await renderInput(nextRowIndex, nextColumnName, null);
|
await renderInput(nextRowIndex, nextColumnName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,16 +481,21 @@ async function renderInput(rowId, field, clickedElement) {
|
||||||
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
|
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
|
||||||
},
|
},
|
||||||
keyup: async (event) => {
|
keyup: async (event) => {
|
||||||
if (event.key === 'Enter')
|
if (event.key === 'Enter') {
|
||||||
|
console.log('destroyInput 4');
|
||||||
await destroyInput(rowId, field, clickedElement);
|
await destroyInput(rowId, field, clickedElement);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
keydown: async (event) => {
|
keydown: async (event) => {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Tab':
|
case 'Tab':
|
||||||
|
console.log('field: ', field);
|
||||||
|
console.log('target: ', event.target);
|
||||||
await handleTabKey(event, rowId, field);
|
await handleTabKey(event, rowId, field);
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
break;
|
break;
|
||||||
case 'Escape':
|
case 'Escape':
|
||||||
|
console.log('destroyInput 5');
|
||||||
await destroyInput(rowId, field, clickedElement);
|
await destroyInput(rowId, field, clickedElement);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -511,6 +530,10 @@ async function updateSelectValue(value, column, row, oldValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function destroyInput(rowIndex, field, clickedElement) {
|
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)
|
if (!clickedElement)
|
||||||
clickedElement = document.querySelector(
|
clickedElement = document.querySelector(
|
||||||
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
|
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
|
||||||
|
@ -523,6 +546,7 @@ async function destroyInput(rowIndex, field, clickedElement) {
|
||||||
child.style.position = '';
|
child.style.position = '';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editingRow.value !== rowIndex || editingField.value !== field) return;
|
if (editingRow.value !== rowIndex || editingField.value !== field) return;
|
||||||
editingRow.value = null;
|
editingRow.value = null;
|
||||||
editingField.value = null;
|
editingField.value = null;
|
||||||
|
@ -540,7 +564,13 @@ async function handleTabNavigation(rowIndex, colName, direction) {
|
||||||
iterations++;
|
iterations++;
|
||||||
newColumnIndex = (newColumnIndex + direction + totalColumns) % totalColumns;
|
newColumnIndex = (newColumnIndex + direction + totalColumns) % totalColumns;
|
||||||
|
|
||||||
if (isEditableColumn(columns[newColumnIndex])) break;
|
if (
|
||||||
|
isEditableColumn(
|
||||||
|
columns[newColumnIndex],
|
||||||
|
CrudModelRef.value.formData[rowIndex],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
break;
|
||||||
} while (iterations < totalColumns);
|
} while (iterations < totalColumns);
|
||||||
|
|
||||||
if (iterations >= totalColumns + 1) return;
|
if (iterations >= totalColumns + 1) return;
|
||||||
|
@ -840,19 +870,19 @@ const handleHeaderSelection = (evt, data) => {
|
||||||
: getToggleIcon(row[col?.name])
|
: getToggleIcon(row[col?.name])
|
||||||
"
|
"
|
||||||
style="color: var(--vn-text-color)"
|
style="color: var(--vn-text-color)"
|
||||||
:class="hasEditableFormat(col)"
|
:class="hasEditableFormat(col, row)"
|
||||||
size="14px"
|
size="14px"
|
||||||
/>
|
/>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-else-if="col?.component === 'checkbox'"
|
v-else-if="col?.component === 'checkbox'"
|
||||||
:name="getCheckboxIcon(row[col?.name])"
|
:name="getCheckboxIcon(row[col?.name])"
|
||||||
style="color: var(--vn-text-color)"
|
style="color: var(--vn-text-color)"
|
||||||
:class="hasEditableFormat(col)"
|
:class="hasEditableFormat(col, row)"
|
||||||
size="14px"
|
size="14px"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
:class="hasEditableFormat(col)"
|
:class="hasEditableFormat(col, row)"
|
||||||
:style="
|
:style="
|
||||||
typeof col?.style == 'function'
|
typeof col?.style == 'function'
|
||||||
? col.style(row)
|
? col.style(row)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/Departme
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import ItemRequestFilter from './ItemRequestFilter.vue';
|
import ItemRequestFilter from './ItemRequestFilter.vue';
|
||||||
import RightMenu from 'src/components/common/RightMenu.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 FormModelPopup from 'src/components/FormModelPopup.vue';
|
||||||
import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
|
import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
|
||||||
import { dashIfEmpty } from 'src/filters';
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
@ -23,8 +22,6 @@ const { notify } = useNotify();
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const denyFormRef = ref(null);
|
const denyFormRef = ref(null);
|
||||||
const denyRequestId = ref(null);
|
const denyRequestId = ref(null);
|
||||||
const denyRequestIndex = ref(null);
|
|
||||||
const itemRequestsOptions = ref([]);
|
|
||||||
const userParams = {
|
const userParams = {
|
||||||
state: 'pending',
|
state: 'pending',
|
||||||
daysOnward: 7,
|
daysOnward: 7,
|
||||||
|
@ -146,7 +143,24 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
component: 'input',
|
component: 'input',
|
||||||
columnClass: 'shrink',
|
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'),
|
label: t('item.buyRequest.concept'),
|
||||||
|
|
|
@ -6,8 +6,7 @@ describe('Item summary', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should clone the item', () => {
|
it('should clone the item', () => {
|
||||||
cy.dataCy('descriptor-more-opts').click();
|
cy.selectDescriptorOption(2);
|
||||||
cy.get('.q-menu > .q-list > :nth-child(2) > .q-item__section').click();
|
|
||||||
cy.dataCy('VnConfirm_confirm').click();
|
cy.dataCy('VnConfirm_confirm').click();
|
||||||
cy.waitForElement('[data-cy="itemTags"]');
|
cy.waitForElement('[data-cy="itemTags"]');
|
||||||
cy.dataCy('itemTags').should('be.visible');
|
cy.dataCy('itemTags').should('be.visible');
|
|
@ -1,15 +1,14 @@
|
||||||
describe('Item list', () => {
|
describe('Item list', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.login('developer');
|
cy.login('buyer');
|
||||||
cy.visit(`/#/item/list`);
|
cy.visit(`/#/item/list`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter the items and redirect to the summary', () => {
|
it('should filter the items and redirect to the summary', () => {
|
||||||
cy.dataCy('Category_select').type('Plant');
|
cy.selectOption('[data-cy="Category_select"]', 'Plant');
|
||||||
cy.get('.q-menu .q-item').contains('Plant').click();
|
cy.selectOption('[data-cy="Type_select"]', 'Anthurium');
|
||||||
cy.dataCy('Type_select').type('Anthurium');
|
|
||||||
cy.get('.q-menu .q-item').contains('Anthurium').click();
|
|
||||||
cy.get('.q-virtual-scroll__content > :nth-child(4) > :nth-child(4)').click();
|
cy.get('.q-virtual-scroll__content > :nth-child(4) > :nth-child(4)').click();
|
||||||
|
cy.url().should('include', '/summary');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an item', () => {
|
it('should create an item', () => {
|
||||||
|
@ -24,8 +23,6 @@ describe('Item list', () => {
|
||||||
cy.fillInForm(data);
|
cy.fillInForm(data);
|
||||||
cy.dataCy('FormModelPopup_save').click();
|
cy.dataCy('FormModelPopup_save').click();
|
||||||
cy.checkNotification('Data created');
|
cy.checkNotification('Data created');
|
||||||
cy.get(
|
cy.url().should('include', '/basic-data');
|
||||||
':nth-child(2) > .q-drawer > .q-drawer__content > .q-scrollarea > .q-scrollarea__container > .q-scrollarea__content',
|
|
||||||
).should('be.visible');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue