WIP - fixes to spreadsheet view
This commit is contained in:
@@ -91,6 +91,12 @@ const editConfig = computed(() => {
|
||||
|
||||
const listPageSize = computed(() => listConfig.value?.pageSize ?? 25)
|
||||
const maxFrontendRecords = computed(() => listConfig.value?.maxFrontendRecords ?? 500)
|
||||
const normalizeRecordId = (id: any) => String(id)
|
||||
|
||||
const draftEdits = ref<Record<string, Record<string, any>>>({})
|
||||
const draftOriginals = ref<Record<string, Record<string, any>>>({})
|
||||
const cellErrors = ref<Record<string, Record<string, string>>>({})
|
||||
const savingDrafts = ref(false)
|
||||
|
||||
// Fetch object definition
|
||||
const fetchObjectDefinition = async () => {
|
||||
@@ -231,20 +237,138 @@ const handleViewChange = async (mode: 'list' | 'spreadsheet') => {
|
||||
|
||||
const handleCellEdit = async (payload: { row: any; field: any; newValue: any; oldValue: any }) => {
|
||||
if (!payload?.row?.id || payload.newValue === payload.oldValue) return
|
||||
try {
|
||||
await updateRecord(payload.row.id, {
|
||||
...payload.row,
|
||||
[payload.field.apiName]: payload.newValue,
|
||||
})
|
||||
} catch (e: any) {
|
||||
error.value = e.message || 'Failed to update record'
|
||||
const record = records.value.find(item => item.id === payload.row.id)
|
||||
if (record) {
|
||||
record[payload.field.apiName] = payload.oldValue
|
||||
const recordKey = normalizeRecordId(payload.row.id)
|
||||
const fieldName = payload.field.apiName
|
||||
const originalRow = draftOriginals.value[recordKey]
|
||||
const originalValue = originalRow && Object.prototype.hasOwnProperty.call(originalRow, fieldName)
|
||||
? originalRow[fieldName]
|
||||
: payload.oldValue
|
||||
|
||||
if (Object.is(payload.newValue, originalValue)) {
|
||||
const nextDrafts = { ...draftEdits.value }
|
||||
const nextRowDrafts = { ...(nextDrafts[recordKey] || {}) }
|
||||
delete nextRowDrafts[fieldName]
|
||||
if (Object.keys(nextRowDrafts).length === 0) {
|
||||
delete nextDrafts[recordKey]
|
||||
} else {
|
||||
nextDrafts[recordKey] = nextRowDrafts
|
||||
}
|
||||
draftEdits.value = nextDrafts
|
||||
|
||||
const nextOriginals = { ...draftOriginals.value }
|
||||
const nextRowOriginals = { ...(nextOriginals[recordKey] || {}) }
|
||||
delete nextRowOriginals[fieldName]
|
||||
if (Object.keys(nextRowOriginals).length === 0) {
|
||||
delete nextOriginals[recordKey]
|
||||
} else {
|
||||
nextOriginals[recordKey] = nextRowOriginals
|
||||
}
|
||||
draftOriginals.value = nextOriginals
|
||||
} else {
|
||||
draftEdits.value = {
|
||||
...draftEdits.value,
|
||||
[recordKey]: {
|
||||
...(draftEdits.value[recordKey] || {}),
|
||||
[fieldName]: payload.newValue,
|
||||
},
|
||||
}
|
||||
if (!originalRow || !Object.prototype.hasOwnProperty.call(originalRow, fieldName)) {
|
||||
draftOriginals.value = {
|
||||
...draftOriginals.value,
|
||||
[recordKey]: {
|
||||
...(draftOriginals.value[recordKey] || {}),
|
||||
[fieldName]: payload.oldValue,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cellErrors.value[recordKey]?.[fieldName]) {
|
||||
const nextErrors = { ...cellErrors.value }
|
||||
const nextRowErrors = { ...(nextErrors[recordKey] || {}) }
|
||||
delete nextRowErrors[fieldName]
|
||||
if (Object.keys(nextRowErrors).length === 0) {
|
||||
delete nextErrors[recordKey]
|
||||
} else {
|
||||
nextErrors[recordKey] = nextRowErrors
|
||||
}
|
||||
cellErrors.value = nextErrors
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveDrafts = async () => {
|
||||
if (Object.keys(draftEdits.value).length === 0) return
|
||||
savingDrafts.value = true
|
||||
const nextErrors: Record<string, Record<string, string>> = {}
|
||||
const nextDrafts = { ...draftEdits.value }
|
||||
const nextOriginals = { ...draftOriginals.value }
|
||||
|
||||
for (const [recordKey, changes] of Object.entries(draftEdits.value)) {
|
||||
const record = records.value.find(item => normalizeRecordId(item.id) === recordKey)
|
||||
if (!record) {
|
||||
delete nextDrafts[recordKey]
|
||||
delete nextOriginals[recordKey]
|
||||
continue
|
||||
}
|
||||
try {
|
||||
await updateRecord(record.id, changes)
|
||||
delete nextDrafts[recordKey]
|
||||
delete nextOriginals[recordKey]
|
||||
} catch (e: any) {
|
||||
const message = e.message || 'Failed to update record'
|
||||
nextErrors[recordKey] = {}
|
||||
for (const fieldName of Object.keys(changes)) {
|
||||
nextErrors[recordKey][fieldName] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draftEdits.value = nextDrafts
|
||||
draftOriginals.value = nextOriginals
|
||||
cellErrors.value = nextErrors
|
||||
savingDrafts.value = false
|
||||
if (Object.keys(nextErrors).length > 0) {
|
||||
error.value = 'Some updates failed. Fix highlighted cells and try again.'
|
||||
}
|
||||
}
|
||||
|
||||
const handleDiscardDrafts = () => {
|
||||
for (const [recordKey, fields] of Object.entries(draftOriginals.value)) {
|
||||
const record = records.value.find(item => normalizeRecordId(item.id) === recordKey)
|
||||
if (!record) continue
|
||||
for (const [fieldName, originalValue] of Object.entries(fields)) {
|
||||
record[fieldName] = originalValue
|
||||
}
|
||||
}
|
||||
draftEdits.value = {}
|
||||
draftOriginals.value = {}
|
||||
cellErrors.value = {}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => records.value.map(record => normalizeRecordId(record.id)),
|
||||
(ids) => {
|
||||
const idSet = new Set(ids)
|
||||
const nextDrafts: Record<string, Record<string, any>> = {}
|
||||
const nextOriginals: Record<string, Record<string, any>> = {}
|
||||
const nextErrors: Record<string, Record<string, string>> = {}
|
||||
|
||||
for (const [recordKey, fields] of Object.entries(draftEdits.value)) {
|
||||
if (idSet.has(recordKey)) nextDrafts[recordKey] = fields
|
||||
}
|
||||
for (const [recordKey, fields] of Object.entries(draftOriginals.value)) {
|
||||
if (idSet.has(recordKey)) nextOriginals[recordKey] = fields
|
||||
}
|
||||
for (const [recordKey, fields] of Object.entries(cellErrors.value)) {
|
||||
if (idSet.has(recordKey)) nextErrors[recordKey] = fields
|
||||
}
|
||||
|
||||
draftEdits.value = nextDrafts
|
||||
draftOriginals.value = nextOriginals
|
||||
cellErrors.value = nextErrors
|
||||
}
|
||||
)
|
||||
|
||||
// Watch for route changes
|
||||
watch(() => route.params, async (newParams, oldParams) => {
|
||||
// Reset current record when navigating to 'new'
|
||||
@@ -311,6 +435,9 @@ onMounted(async () => {
|
||||
:data="records"
|
||||
:loading="dataLoading"
|
||||
:total-count="totalCount"
|
||||
:draft-edits="draftEdits"
|
||||
:cell-errors="cellErrors"
|
||||
:saving-drafts="savingDrafts"
|
||||
selectable
|
||||
@row-click="handleRowClick"
|
||||
@create="handleCreate"
|
||||
@@ -320,6 +447,8 @@ onMounted(async () => {
|
||||
@load-more="handleLoadMore"
|
||||
@view-change="handleViewChange"
|
||||
@cell-edit="handleCellEdit"
|
||||
@save-drafts="handleSaveDrafts"
|
||||
@discard-drafts="handleDiscardDrafts"
|
||||
/>
|
||||
|
||||
<!-- Detail View -->
|
||||
|
||||
Reference in New Issue
Block a user