mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-26 13:44:41 +00:00
Merge branch 'prevent-view-update-with-wrong-data' into 'develop'
Prevent view from updated state with data from wrong view when pending request completes Closes #3398 See merge request baserow/baserow!3165
This commit is contained in:
commit
b21e5fc47b
5 changed files with 89 additions and 8 deletions
changelog/entries/unreleased/bug
premium/web-frontend/modules/baserow_premium/store/view
web-frontend/modules/database/store/view
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "bug",
|
||||
"message": "Prevent view from updated state with data from wrong view when pending request completes.",
|
||||
"issue_number": 3398,
|
||||
"bullet_points": [],
|
||||
"created_at": "2025-02-18"
|
||||
}
|
|
@ -304,6 +304,7 @@ export const actions = {
|
|||
{ commit, getters, rootGetters },
|
||||
{ dateTime, fields, includeFieldOptions = false }
|
||||
) {
|
||||
const calendarId = getters.getLastCalendarId
|
||||
commit('SET_SELECTED_DATE', dateTime)
|
||||
|
||||
const df = getters.getDateField(fields)
|
||||
|
@ -335,6 +336,12 @@ export const actions = {
|
|||
publicUrl: rootGetters['page/view/public/getIsPublic'],
|
||||
publicAuthToken: rootGetters['page/view/public/getAuthToken'],
|
||||
})
|
||||
// Don't do anything if the calendarId does not match the current view calendarId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (calendarId !== getters.getLastCalendarId) {
|
||||
return
|
||||
}
|
||||
const lastRequest = dateTime.isSame(getters.getSelectedDate(fields))
|
||||
if (lastRequest) {
|
||||
Object.keys(data.rows).forEach((key) => {
|
||||
|
@ -390,6 +397,12 @@ export const actions = {
|
|||
publicAuthToken: rootGetters['page/view/public/getAuthToken'],
|
||||
filters,
|
||||
})
|
||||
// Don't do anything if the calendarId does not match the current view calendarId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (calendarId !== getters.getLastCalendarId) {
|
||||
return
|
||||
}
|
||||
const newRows = data.rows[date].results
|
||||
const newCount = data.rows[date].count
|
||||
newRows.forEach((row) => {
|
||||
|
|
|
@ -211,6 +211,7 @@ export const actions = {
|
|||
}
|
||||
) {
|
||||
commit('SET_ADHOC_FILTERING', adhocFiltering)
|
||||
commit('SET_LAST_KANBAN_ID', kanbanId)
|
||||
const view = rootGetters['view/get'](kanbanId)
|
||||
const { data } = await KanbanService(this.$client).fetchRows({
|
||||
kanbanId,
|
||||
|
@ -222,10 +223,15 @@ export const actions = {
|
|||
publicAuthToken: rootGetters['page/view/public/getAuthToken'],
|
||||
filters: getFilters(view, adhocFiltering),
|
||||
})
|
||||
// Don't do anything if the kanbanId does not match the current view kanbanId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (kanbanId !== getters.getLastKanbanId) {
|
||||
return
|
||||
}
|
||||
Object.keys(data.rows).forEach((key) => {
|
||||
populateStack(data.rows[key], data)
|
||||
})
|
||||
commit('SET_LAST_KANBAN_ID', kanbanId)
|
||||
commit('SET_SINGLE_SELECT_FIELD_ID', singleSelectFieldId)
|
||||
commit('REPLACE_ALL_STACKS', data.rows)
|
||||
if (includeFieldOptions) {
|
||||
|
@ -241,10 +247,11 @@ export const actions = {
|
|||
{ dispatch, commit, getters, rootGetters },
|
||||
{ selectOptionId }
|
||||
) {
|
||||
const kanbanId = getters.getLastKanbanId
|
||||
const stack = getters.getStack(selectOptionId)
|
||||
const view = rootGetters['view/get'](getters.getLastKanbanId)
|
||||
const view = rootGetters['view/get'](kanbanId)
|
||||
const { data } = await KanbanService(this.$client).fetchRows({
|
||||
kanbanId: getters.getLastKanbanId,
|
||||
kanbanId,
|
||||
limit: getters.getBufferRequestSize,
|
||||
offset: 0,
|
||||
includeFieldOptions: false,
|
||||
|
@ -259,6 +266,12 @@ export const actions = {
|
|||
publicAuthToken: rootGetters['page/view/public/getAuthToken'],
|
||||
filters: getFilters(view, getters.getAdhocFiltering),
|
||||
})
|
||||
// Don't do anything if the kanbanId does not match the current view kanbanId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (kanbanId !== getters.getLastKanbanId) {
|
||||
return
|
||||
}
|
||||
const count = data.rows[selectOptionId].count
|
||||
const rows = data.rows[selectOptionId].results
|
||||
rows.forEach((row) => {
|
||||
|
|
|
@ -321,6 +321,12 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
filters: getFilters(view, adhocFiltering),
|
||||
...initialRowArguments,
|
||||
})
|
||||
// Don't do anything if the viewId does not match the current view viewId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (viewId !== getters.getViewId) {
|
||||
return
|
||||
}
|
||||
const rows = Array(data.count).fill(null)
|
||||
data.results.forEach((row, index) => {
|
||||
const metadata = extractRowMetadata(data, row.id)
|
||||
|
@ -339,6 +345,7 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
{ dispatch, getters, commit, rootGetters },
|
||||
parameters
|
||||
) {
|
||||
const viewId = getters.getViewId
|
||||
const { startIndex, endIndex } = parameters
|
||||
|
||||
// If the store is already fetching a set of pages, we're temporarily storing
|
||||
|
@ -377,7 +384,7 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
return
|
||||
}
|
||||
|
||||
const view = rootGetters['view/get'](getters.getViewId)
|
||||
const view = rootGetters['view/get'](viewId)
|
||||
|
||||
// We can only make one request at the same time, so we're going to set the
|
||||
// fetching state to `true` to prevent multiple requests being fired
|
||||
|
@ -386,7 +393,7 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
lastRequestController = new AbortController()
|
||||
try {
|
||||
const { data } = await service(this.$client).fetchRows({
|
||||
viewId: getters.getViewId,
|
||||
viewId,
|
||||
offset: rangeToFetch.offset,
|
||||
limit: rangeToFetch.limit,
|
||||
signal: lastRequestController.signal,
|
||||
|
@ -397,6 +404,12 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
orderBy: getOrderBy(view, getters.getAdhocSorting),
|
||||
filters: getFilters(view, getters.getAdhocFiltering),
|
||||
})
|
||||
// Don't do anything if the viewId does not match the current view viewId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (viewId !== getters.getViewId) {
|
||||
return
|
||||
}
|
||||
commit('UPDATE_ROWS', {
|
||||
offset: rangeToFetch.offset,
|
||||
rows: data.results,
|
||||
|
@ -429,6 +442,7 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
{ dispatch, commit, getters, rootGetters },
|
||||
{ fields, adhocFiltering, adhocSorting, includeFieldOptions = false }
|
||||
) {
|
||||
const viewId = getters.getViewId
|
||||
commit('SET_ADHOC_FILTERING', adhocFiltering)
|
||||
commit('SET_ADHOC_SORTING', adhocSorting)
|
||||
// If another refresh or fetch request is currently running, we need to cancel
|
||||
|
@ -439,7 +453,7 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
}
|
||||
|
||||
lastRequestController = new AbortController()
|
||||
const view = rootGetters['view/get'](getters.getViewId)
|
||||
const view = rootGetters['view/get'](viewId)
|
||||
try {
|
||||
// We first need to fetch the count of all rows because we need to know how
|
||||
// many rows there are in total to estimate what are new visible range it
|
||||
|
@ -448,7 +462,7 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
const {
|
||||
data: { count },
|
||||
} = await service(this.$client).fetchCount({
|
||||
viewId: getters.getViewId,
|
||||
viewId,
|
||||
signal: lastRequestController.signal,
|
||||
search: getters.getServerSearchTerm,
|
||||
searchMode: getDefaultSearchModeFromEnv(this.$config),
|
||||
|
@ -487,7 +501,7 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
|
||||
// Only fetch visible rows if there are any.
|
||||
const { data } = await service(this.$client).fetchRows({
|
||||
viewId: getters.getViewId,
|
||||
viewId,
|
||||
offset: rangeToFetch.offset,
|
||||
limit: rangeToFetch.limit,
|
||||
includeFieldOptions,
|
||||
|
@ -500,6 +514,13 @@ export default ({ service, customPopulateRow, fieldOptions }) => {
|
|||
filters: getFilters(view, adhocFiltering),
|
||||
})
|
||||
|
||||
// Don't do anything if the viewId does not match the current view viewId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (viewId !== getters.getViewId) {
|
||||
return
|
||||
}
|
||||
|
||||
data.results.forEach((row, index) => {
|
||||
const metadata = extractRowMetadata(data, row.id)
|
||||
rows[rangeToFetch.offset + index] = populateRow(row, metadata)
|
||||
|
|
|
@ -777,6 +777,13 @@ export const actions = {
|
|||
filters: getFilters(view, getters.getAdhocFiltering),
|
||||
})
|
||||
.then(({ data }) => {
|
||||
// Don't do anything if the gridId does not match the current view gridId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (gridId !== getters.getLastGridId) {
|
||||
return
|
||||
}
|
||||
|
||||
data.results.forEach((row) => {
|
||||
const metadata = extractRowMetadata(data, row.id)
|
||||
populateRow(row, metadata)
|
||||
|
@ -943,6 +950,12 @@ export const actions = {
|
|||
orderBy: getOrderBy(view, adhocSorting),
|
||||
filters: getFilters(view, adhocFiltering),
|
||||
})
|
||||
// Don't do anything if the gridId does not match the current view gridId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (gridId !== getters.getLastGridId) {
|
||||
return
|
||||
}
|
||||
data.results.forEach((row) => {
|
||||
const metadata = extractRowMetadata(data, row.id)
|
||||
populateRow(row, metadata)
|
||||
|
@ -1028,6 +1041,12 @@ export const actions = {
|
|||
}))
|
||||
)
|
||||
.then(({ data, offset }) => {
|
||||
// Don't do anything if the gridId does not match the current view gridId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (gridId !== getters.getLastGridId) {
|
||||
return
|
||||
}
|
||||
// If there are results we can replace the existing rows so that the user stays
|
||||
// at the same scroll offset.
|
||||
data.results.forEach((row) => {
|
||||
|
@ -1190,6 +1209,7 @@ export const actions = {
|
|||
const isPublic = rootGetters['page/view/public/getIsPublic']
|
||||
const search = getters.getActiveSearchTerm
|
||||
const fieldOptions = getters.getAllFieldOptions
|
||||
const gridId = getters.getLastGridId
|
||||
let atLeastOneAggregation = false
|
||||
|
||||
Object.entries(fieldOptions).forEach(([fieldId, options]) => {
|
||||
|
@ -1239,6 +1259,13 @@ export const actions = {
|
|||
const { data } = await lastAggregationRequest.request
|
||||
lastAggregationRequest.request = null
|
||||
|
||||
// Don't do anything if the gridId does not match the current view gridId
|
||||
// because that probably means the user switched to another view or table, and
|
||||
// the data that is returned here shouldn't do anything.
|
||||
if (gridId !== getters.getLastGridId) {
|
||||
return
|
||||
}
|
||||
|
||||
Object.entries(fieldOptions).forEach(([fieldId, options]) => {
|
||||
if (options.aggregation_raw_type) {
|
||||
commit('SET_FIELD_AGGREGATION_DATA', {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue