mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-07 22:35:36 +00:00
Resolve "Web-frontend results into error when switching rapidly between tables"
This commit is contained in:
parent
3d56805128
commit
fd62565f86
4 changed files with 108 additions and 59 deletions
|
@ -11,6 +11,8 @@
|
|||
first option with that value.
|
||||
* The API now returns appropriate errors when trying to create a field with a name which is too long.
|
||||
* Importing table data with a column name that is too long will now truncate that name.
|
||||
* Fixed error when rapidly switching between template tables or views in the template
|
||||
preview.
|
||||
|
||||
## Released (2021-08-11)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
:table-loading="tableLoading"
|
||||
:read-only="true"
|
||||
store-prefix="template/"
|
||||
@selected-view="selectView($event.id)"
|
||||
@selected-view="selectView({ viewId: $event.id })"
|
||||
></Table>
|
||||
</template>
|
||||
|
||||
|
@ -20,6 +20,7 @@ import FieldService from '@baserow/modules/database/services/field'
|
|||
import { populateField } from '@baserow/modules/database/store/field'
|
||||
import ViewService from '@baserow/modules/database/services/view'
|
||||
import { populateView } from '@baserow/modules/database/store/view'
|
||||
import { Mutex } from 'async-mutex'
|
||||
|
||||
export default {
|
||||
name: 'TableTemplate',
|
||||
|
@ -37,9 +38,9 @@ export default {
|
|||
fields: [],
|
||||
primary: {},
|
||||
views: [],
|
||||
selectedViewId: null,
|
||||
view: {},
|
||||
tableLoading: true,
|
||||
mutex: new Mutex(),
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -51,78 +52,111 @@ export default {
|
|||
this.fetchTable(this.pageValue.database, this.pageValue.table)
|
||||
},
|
||||
methods: {
|
||||
async runExclusiveUnlessAlreadyLocked({ callback, alreadyLocked = false }) {
|
||||
if (alreadyLocked) {
|
||||
return await callback()
|
||||
} else {
|
||||
return await this.mutex.runExclusive(callback)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Fetches and prepares all the table, field and view data for the provided
|
||||
* database and table.
|
||||
*/
|
||||
async fetchTable(database, table) {
|
||||
this.tableLoading = true
|
||||
this.database = database
|
||||
this.table = table
|
||||
await this.runExclusiveUnlessAlreadyLocked({
|
||||
callback: async () => {
|
||||
// If the new table is already selected, then we don't need to do anything.
|
||||
if (table.id === this.table.id) {
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch and prepare the fields of the given table. The primary field is
|
||||
// extracted from the array and moved to a separate object because that is what
|
||||
// the `Table` components expects.
|
||||
const { data: fieldsData } = await FieldService(this.$client).fetchAll(
|
||||
table.id
|
||||
)
|
||||
fieldsData.forEach((part, index, d) => {
|
||||
populateField(fieldsData[index], this.$registry)
|
||||
this.tableLoading = true
|
||||
this.database = database
|
||||
this.table = table
|
||||
|
||||
// Fetch and prepare the fields of the given table. The primary field is
|
||||
// extracted from the array and moved to a separate object because that is what
|
||||
// the `Table` components expects.
|
||||
const { data: fieldsData } = await FieldService(
|
||||
this.$client
|
||||
).fetchAll(table.id)
|
||||
fieldsData.forEach((part, index, d) => {
|
||||
populateField(fieldsData[index], this.$registry)
|
||||
})
|
||||
const primaryIndex = fieldsData.findIndex(
|
||||
(item) => item.primary === true
|
||||
)
|
||||
const primary =
|
||||
primaryIndex !== -1 ? fieldsData.splice(primaryIndex, 1)[0] : null
|
||||
this.fields = fieldsData
|
||||
this.primary = primary
|
||||
|
||||
// Fetch and prepare the views of the given table.
|
||||
const { data: viewsData } = await ViewService(this.$client).fetchAll(
|
||||
table.id,
|
||||
true,
|
||||
true
|
||||
)
|
||||
viewsData.forEach((part, index, d) => {
|
||||
populateView(viewsData[index], this.$registry)
|
||||
})
|
||||
this.views = viewsData
|
||||
|
||||
// After selecting the table, the user expects to see the table data and that is
|
||||
// only possible if a view is selected. By calling the `selectView` method
|
||||
// without parameters, the first view is selected.
|
||||
await this.selectView({ alreadyLocked: true })
|
||||
},
|
||||
})
|
||||
const primaryIndex = fieldsData.findIndex((item) => item.primary === true)
|
||||
const primary =
|
||||
primaryIndex !== -1 ? fieldsData.splice(primaryIndex, 1)[0] : null
|
||||
this.fields = fieldsData
|
||||
this.primary = primary
|
||||
|
||||
// Fetch and prepare the views of the given table.
|
||||
const { data: viewsData } = await ViewService(this.$client).fetchAll(
|
||||
table.id,
|
||||
true,
|
||||
true
|
||||
)
|
||||
viewsData.forEach((part, index, d) => {
|
||||
populateView(viewsData[index], this.$registry)
|
||||
})
|
||||
this.views = viewsData
|
||||
|
||||
// After selecting the table, the user expects to see the table data and that is
|
||||
// only possible if a view is selected. By calling the `selectView` method
|
||||
// without parameters, the first view is selected.
|
||||
await this.selectView()
|
||||
},
|
||||
/**
|
||||
* Selects the view with the given `viewId`. If no `viewId` is provided, then the
|
||||
* first view will be selected.
|
||||
*/
|
||||
async selectView(viewId = null) {
|
||||
this.tableLoading = true
|
||||
|
||||
// If no viewId is provided, we want to select the first the first view.
|
||||
const firstView = this.views.length > 0 ? this.views[0] : null
|
||||
if (viewId === null && firstView !== null) {
|
||||
viewId = firstView.id
|
||||
async selectView({ viewId = null, alreadyLocked = false }) {
|
||||
// If the new view is already selected, we don't need to do anything.
|
||||
if (viewId === this.view.id) {
|
||||
return
|
||||
}
|
||||
|
||||
// Update the selected state in all the views.
|
||||
this.views.forEach((view) => {
|
||||
view._.selected = view.id === viewId
|
||||
await this.runExclusiveUnlessAlreadyLocked({
|
||||
alreadyLocked,
|
||||
callback: async () => {
|
||||
// If the new view is already selected, we don't need to do anything.
|
||||
if (viewId === this.view.id) {
|
||||
return
|
||||
}
|
||||
|
||||
this.tableLoading = true
|
||||
|
||||
// If no viewId is provided, we want to select the first the first view.
|
||||
const firstView = this.views.length > 0 ? this.views[0] : null
|
||||
if (viewId === null && firstView !== null) {
|
||||
viewId = firstView.id
|
||||
}
|
||||
|
||||
// Update the selected state in all the views.
|
||||
this.views.forEach((view) => {
|
||||
view._.selected = view.id === viewId
|
||||
})
|
||||
|
||||
const view = this.views.find((item) => item.id === viewId)
|
||||
this.view = view
|
||||
|
||||
// It might be possible that the view also has some stores that need to be
|
||||
// filled with initial data, so we're going to call the fetch function here.
|
||||
const type = this.$registry.get('view', view.type)
|
||||
await type.fetch(
|
||||
{ store: this.$store },
|
||||
view,
|
||||
this.fields,
|
||||
this.primary,
|
||||
'template/'
|
||||
)
|
||||
this.tableLoading = false
|
||||
},
|
||||
})
|
||||
|
||||
const view = this.views.find((item) => item.id === viewId)
|
||||
this.view = view
|
||||
|
||||
// It might be possible that the view also has some stores that need to be
|
||||
// filled with initial data, so we're going to call the fetch function here.
|
||||
const type = this.$registry.get('view', view.type)
|
||||
await type.fetch(
|
||||
{ store: this.$store },
|
||||
view,
|
||||
this.fields,
|
||||
this.primary,
|
||||
'template/'
|
||||
)
|
||||
this.tableLoading = false
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||
"@nuxtjs/axios": "^5.13.6",
|
||||
"@nuxtjs/i18n": "^7.0.1",
|
||||
"async-mutex": "^0.3.1",
|
||||
"axios": "^0.21.0",
|
||||
"bignumber.js": "^9.0.1",
|
||||
"chart.js": "2.9.4",
|
||||
|
|
|
@ -2515,6 +2515,13 @@ async-foreach@^0.1.3:
|
|||
resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
|
||||
integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
|
||||
|
||||
async-mutex@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.3.1.tgz#7033af665f1c7cebed8b878267a43ba9e77c5f67"
|
||||
integrity sha512-vRfQwcqBnJTLzVQo72Sf7KIUbcSUP5hNchx6udI1U6LuPQpfePgdjJzlCe76yFZ8pxlLjn9lwcl/Ya0TSOv0Tw==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
|
@ -11512,6 +11519,11 @@ tslib@^2.0.3:
|
|||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
||||
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||
|
||||
tslib@^2.1.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
|
||||
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
||||
|
|
Loading…
Add table
Reference in a new issue