Add multiple validation improvements
This commit is contained in:
parent
6c203a1e66
commit
4a6713e9d3
|
@ -24,6 +24,12 @@
|
|||
let lastSearchId
|
||||
let results
|
||||
|
||||
$: {
|
||||
if (focused) {
|
||||
console.log(value)
|
||||
}
|
||||
}
|
||||
|
||||
$: oneRowOnly = schema?.relationshipType === "one-to-many"
|
||||
$: editable = focused && !readonly
|
||||
$: results = getResults(searchResults, value)
|
||||
|
@ -52,6 +58,7 @@
|
|||
if (!row?._id) {
|
||||
return false
|
||||
}
|
||||
console.log(lookupMap)
|
||||
return lookupMap?.[row._id] === true
|
||||
}
|
||||
|
||||
|
@ -192,11 +199,7 @@
|
|||
}
|
||||
candidateIndex = null
|
||||
}
|
||||
|
||||
// Clear search state to allow finding a new row again
|
||||
searchString = null
|
||||
searchResults = []
|
||||
lastSearchString = null
|
||||
close()
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { debounce } from "../../../utils/utils"
|
||||
|
||||
const {
|
||||
rows,
|
||||
enrichedRows,
|
||||
focusedCellId,
|
||||
visibleColumns,
|
||||
focusedRow,
|
||||
|
@ -63,7 +63,7 @@
|
|||
}
|
||||
|
||||
const selectFirstCell = () => {
|
||||
const firstRow = $rows[0]
|
||||
const firstRow = $enrichedRows[0]
|
||||
if (!firstRow) {
|
||||
return
|
||||
}
|
||||
|
@ -102,7 +102,7 @@
|
|||
if (!$focusedRow) {
|
||||
return
|
||||
}
|
||||
const newRow = $rows[$focusedRow.__idx + delta]
|
||||
const newRow = $enrichedRows[$focusedRow.__idx + delta]
|
||||
if (newRow) {
|
||||
const split = $focusedCellId.split("-")
|
||||
$focusedCellId = `${newRow._id}-${split[1]}`
|
||||
|
|
|
@ -13,18 +13,8 @@ export const createStores = () => {
|
|||
const filter = writable([])
|
||||
const loaded = writable(false)
|
||||
const sort = writable(initialSortState)
|
||||
|
||||
// Enrich rows with an index property
|
||||
const enrichedRows = derived(
|
||||
rows,
|
||||
$rows => {
|
||||
return $rows.map((row, idx) => ({
|
||||
...row,
|
||||
__idx: idx,
|
||||
}))
|
||||
},
|
||||
[]
|
||||
)
|
||||
const rowChangeCache = writable({})
|
||||
const inProgressChanges = writable({})
|
||||
|
||||
// Generate a lookup map to quick find a row by ID
|
||||
const rowLookupMap = derived(
|
||||
|
@ -40,15 +30,14 @@ export const createStores = () => {
|
|||
)
|
||||
|
||||
return {
|
||||
rows: {
|
||||
...rows,
|
||||
subscribe: enrichedRows.subscribe,
|
||||
},
|
||||
rows,
|
||||
rowLookupMap,
|
||||
table,
|
||||
filter,
|
||||
loaded,
|
||||
sort,
|
||||
rowChangeCache,
|
||||
inProgressChanges,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,6 +55,9 @@ export const deriveStores = context => {
|
|||
validation,
|
||||
focusedCellId,
|
||||
columns,
|
||||
rowChangeCache,
|
||||
inProgressChanges,
|
||||
previousFocusedRowId,
|
||||
} = context
|
||||
const instanceLoaded = writable(false)
|
||||
const fetch = writable(null)
|
||||
|
@ -73,6 +65,19 @@ export const deriveStores = context => {
|
|||
// Local cache of row IDs to speed up checking if a row exists
|
||||
let rowCacheMap = {}
|
||||
|
||||
// Enrich rows with an index property and any pending changes
|
||||
const enrichedRows = derived(
|
||||
[rows, rowChangeCache],
|
||||
([$rows, $rowChangeCache]) => {
|
||||
return $rows.map((row, idx) => ({
|
||||
...row,
|
||||
...$rowChangeCache[row._id],
|
||||
__idx: idx,
|
||||
}))
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
// Reset everything when table ID changes
|
||||
let unsubscribe = null
|
||||
tableId.subscribe($tableId => {
|
||||
|
@ -153,6 +158,7 @@ export const deriveStores = context => {
|
|||
// state, storing error messages against relevant cells
|
||||
const handleValidationError = (rowId, error) => {
|
||||
if (error?.json?.validationErrors) {
|
||||
// Normal validation error
|
||||
const keys = Object.keys(error.json.validationErrors)
|
||||
const $columns = get(columns)
|
||||
for (let column of keys) {
|
||||
|
@ -173,7 +179,8 @@ export const deriveStores = context => {
|
|||
// Focus the first cell with an error
|
||||
focusedCellId.set(`${rowId}-${keys[0]}`)
|
||||
} else {
|
||||
notifications.error(`Error saving row: ${error?.message}`)
|
||||
// Some other error - just update the current cell
|
||||
validation.actions.setError(get(focusedCellId), error?.message || "Error")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,25 +261,42 @@ export const deriveStores = context => {
|
|||
}
|
||||
|
||||
// Immediately update state so that the change is reflected
|
||||
let newRow = { ...row, [column]: value }
|
||||
rows.update(state => {
|
||||
state[index] = { ...newRow }
|
||||
return state
|
||||
})
|
||||
rowChangeCache.update(state => ({
|
||||
...state,
|
||||
[rowId]: {
|
||||
...state[rowId],
|
||||
[column]: value,
|
||||
},
|
||||
}))
|
||||
|
||||
// Save change
|
||||
delete newRow.__idx
|
||||
try {
|
||||
await API.saveRow(newRow)
|
||||
} catch (error) {
|
||||
handleValidationError(newRow._id, error)
|
||||
inProgressChanges.update(state => ({
|
||||
...state,
|
||||
[rowId]: true,
|
||||
}))
|
||||
const newRow = { ...row, ...get(rowChangeCache)[rowId] }
|
||||
const saved = await API.saveRow(newRow)
|
||||
|
||||
// Revert change
|
||||
// Update state after a successful change
|
||||
rows.update(state => {
|
||||
state[index] = row
|
||||
return state
|
||||
})
|
||||
state[index] = {
|
||||
...newRow,
|
||||
_rev: saved._rev,
|
||||
}
|
||||
return state.slice()
|
||||
})
|
||||
rowChangeCache.update(state => ({
|
||||
...state,
|
||||
[rowId]: null,
|
||||
}))
|
||||
} catch (error) {
|
||||
handleValidationError(rowId, error)
|
||||
}
|
||||
inProgressChanges.update(state => ({
|
||||
...state,
|
||||
[rowId]: false,
|
||||
}))
|
||||
}
|
||||
|
||||
// Deletes an array of rows
|
||||
|
@ -338,7 +362,18 @@ export const deriveStores = context => {
|
|||
return get(rowLookupMap)[id] != null
|
||||
}
|
||||
|
||||
// Wipe the row change cache when changing row
|
||||
previousFocusedRowId.subscribe(id => {
|
||||
if (!get(inProgressChanges)[id]) {
|
||||
rowChangeCache.update(state => ({
|
||||
...state,
|
||||
[id]: null,
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
enrichedRows,
|
||||
rows: {
|
||||
...rows,
|
||||
actions: {
|
||||
|
|
|
@ -6,9 +6,29 @@ export const createStores = () => {
|
|||
const selectedRows = writable({})
|
||||
const hoveredRowId = writable(null)
|
||||
const rowHeight = writable(36)
|
||||
const previousFocusedRowId = writable(null)
|
||||
|
||||
// Derive the current focused row ID
|
||||
const focusedRowId = derived(
|
||||
focusedCellId,
|
||||
$focusedCellId => {
|
||||
return $focusedCellId?.split("-")[0]
|
||||
},
|
||||
null
|
||||
)
|
||||
|
||||
// Remember the last focused row ID so that we can store the previous one
|
||||
let lastFocusedRowId = null
|
||||
focusedRowId.subscribe(id => {
|
||||
previousFocusedRowId.set(lastFocusedRowId)
|
||||
lastFocusedRowId = id
|
||||
})
|
||||
|
||||
return {
|
||||
focusedCellId,
|
||||
focusedCellAPI,
|
||||
focusedRowId,
|
||||
previousFocusedRowId,
|
||||
selectedRows,
|
||||
hoveredRowId,
|
||||
rowHeight,
|
||||
|
@ -16,13 +36,19 @@ export const createStores = () => {
|
|||
}
|
||||
|
||||
export const deriveStores = context => {
|
||||
const { focusedCellId, selectedRows, hoveredRowId, rows, rowLookupMap } =
|
||||
context
|
||||
const {
|
||||
rows,
|
||||
focusedCellId,
|
||||
selectedRows,
|
||||
hoveredRowId,
|
||||
enrichedRows,
|
||||
rowLookupMap,
|
||||
} = context
|
||||
|
||||
// Derive the row that contains the selected cell
|
||||
const focusedRow = derived(
|
||||
[focusedCellId, rowLookupMap, rows],
|
||||
([$focusedCellId, $rowLookupMap, $rows]) => {
|
||||
[focusedCellId, rowLookupMap, enrichedRows],
|
||||
([$focusedCellId, $rowLookupMap, $enrichedRows]) => {
|
||||
const rowId = $focusedCellId?.split("-")[0]
|
||||
|
||||
if (rowId === "new") {
|
||||
|
@ -31,7 +57,7 @@ export const deriveStores = context => {
|
|||
} else {
|
||||
// All normal rows
|
||||
const index = $rowLookupMap[rowId]
|
||||
return $rows[index]
|
||||
return $enrichedRows[index]
|
||||
}
|
||||
},
|
||||
null
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { writable, get, derived } from "svelte/store"
|
||||
import { writable, get } from "svelte/store"
|
||||
|
||||
export const createStores = () => {
|
||||
const validation = writable({})
|
||||
|
@ -24,29 +24,22 @@ export const createStores = () => {
|
|||
}
|
||||
|
||||
export const deriveStores = context => {
|
||||
const { validation, focusedRow, columns, stickyColumn } = context
|
||||
const focusedRowId = derived(focusedRow, $focusedRow => $focusedRow?._id)
|
||||
const { validation, previousFocusedRowId, columns, stickyColumn } = context
|
||||
|
||||
// Store the row ID that was previously focused, so we can remove errors from
|
||||
// it when we focus a new row
|
||||
let previousFocusedRowId = null
|
||||
focusedRowId.subscribe(id => {
|
||||
// Remove validation errors from previous focused row
|
||||
if (previousFocusedRowId) {
|
||||
previousFocusedRowId.subscribe(id => {
|
||||
if (id) {
|
||||
const $columns = get(columns)
|
||||
const $stickyColumn = get(stickyColumn)
|
||||
validation.update(state => {
|
||||
$columns.forEach(column => {
|
||||
state[`${previousFocusedRowId}-${column.name}`] = null
|
||||
state[`${id}-${column.name}`] = null
|
||||
})
|
||||
if ($stickyColumn) {
|
||||
state[`${previousFocusedRowId}-${$stickyColumn.name}`] = null
|
||||
state[`${id}-${$stickyColumn.name}`] = null
|
||||
}
|
||||
return state
|
||||
})
|
||||
}
|
||||
|
||||
// Store row ID
|
||||
previousFocusedRowId = id
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ export const deriveStores = context => {
|
|||
const {
|
||||
rowHeight,
|
||||
visibleColumns,
|
||||
rows,
|
||||
enrichedRows,
|
||||
scrollTop,
|
||||
scrollLeft,
|
||||
width,
|
||||
|
@ -29,9 +29,9 @@ export const deriveStores = context => {
|
|||
0
|
||||
)
|
||||
const renderedRows = derived(
|
||||
[rows, scrolledRowCount, visualRowCapacity],
|
||||
([$rows, $scrolledRowCount, $visualRowCapacity]) => {
|
||||
return $rows.slice(
|
||||
[enrichedRows, scrolledRowCount, visualRowCapacity],
|
||||
([$enrichedRows, $scrolledRowCount, $visualRowCapacity]) => {
|
||||
return $enrichedRows.slice(
|
||||
$scrolledRowCount,
|
||||
$scrolledRowCount + $visualRowCapacity
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue