2023-02-27 14:33:19 +00:00
|
|
|
<template>
|
2023-03-22 15:24:55 +00:00
|
|
|
<div class="page-editor">
|
2024-11-28 08:47:54 +00:00
|
|
|
<PageHeader />
|
2023-03-22 15:24:55 +00:00
|
|
|
<div class="layout__col-2-2 page-editor__content">
|
|
|
|
<div :style="{ width: `calc(100% - ${panelWidth}px)` }">
|
2023-03-17 10:59:23 +00:00
|
|
|
<PagePreview />
|
|
|
|
</div>
|
2023-08-16 13:16:52 +00:00
|
|
|
<div
|
|
|
|
class="page-editor__side-panel"
|
|
|
|
:style="{ width: `${panelWidth}px` }"
|
|
|
|
>
|
2023-03-22 15:24:55 +00:00
|
|
|
<PageSidePanels />
|
|
|
|
</div>
|
2023-03-17 10:59:23 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2023-02-27 14:33:19 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import { StoreItemLookupError } from '@baserow/modules/core/errors'
|
2023-06-22 14:23:00 +00:00
|
|
|
import PageHeader from '@baserow/modules/builder/components/page/header/PageHeader'
|
2023-03-17 10:59:23 +00:00
|
|
|
import PagePreview from '@baserow/modules/builder/components/page/PagePreview'
|
2023-03-22 15:24:55 +00:00
|
|
|
import PageSidePanels from '@baserow/modules/builder/components/page/PageSidePanels'
|
2023-09-21 14:24:02 +00:00
|
|
|
import { DataProviderType } from '@baserow/modules/core/dataProviderTypes'
|
2024-03-21 16:13:59 +00:00
|
|
|
import { BuilderApplicationType } from '@baserow/modules/builder/applicationTypes'
|
2024-07-18 13:10:31 +00:00
|
|
|
import ApplicationBuilderFormulaInput from '@baserow/modules/builder/components/ApplicationBuilderFormulaInput'
|
2024-03-01 13:50:13 +00:00
|
|
|
import _ from 'lodash'
|
2023-02-27 14:33:19 +00:00
|
|
|
|
2024-02-28 20:20:30 +00:00
|
|
|
const mode = 'editing'
|
|
|
|
|
2023-02-27 14:33:19 +00:00
|
|
|
export default {
|
2023-03-22 15:24:55 +00:00
|
|
|
name: 'PageEditor',
|
|
|
|
components: { PagePreview, PageHeader, PageSidePanels },
|
2023-05-11 15:27:17 +00:00
|
|
|
provide() {
|
2023-12-15 09:04:09 +00:00
|
|
|
return {
|
2024-05-02 14:25:42 +00:00
|
|
|
workspace: this.workspace,
|
2023-12-15 09:04:09 +00:00
|
|
|
builder: this.builder,
|
2024-11-28 08:47:54 +00:00
|
|
|
currentPage: this.currentPage,
|
2024-02-28 20:20:30 +00:00
|
|
|
mode,
|
2024-07-18 13:10:31 +00:00
|
|
|
formulaComponent: ApplicationBuilderFormulaInput,
|
2024-05-24 10:35:59 +00:00
|
|
|
applicationContext: this.applicationContext,
|
2023-12-15 09:04:09 +00:00
|
|
|
}
|
2023-05-11 15:27:17 +00:00
|
|
|
},
|
2024-10-17 15:49:51 +00:00
|
|
|
|
2024-02-28 20:20:30 +00:00
|
|
|
/**
|
2024-05-02 14:25:42 +00:00
|
|
|
* When the route is updated we want to unselect the element
|
2024-02-28 20:20:30 +00:00
|
|
|
*/
|
|
|
|
beforeRouteUpdate(to, from, next) {
|
|
|
|
// Unselect previously selected element
|
2025-02-05 10:44:06 +01:00
|
|
|
const currentBuilder = this.$store.getters['application/get'](
|
|
|
|
parseInt(from.params.builderId)
|
|
|
|
)
|
2024-05-02 14:25:42 +00:00
|
|
|
this.$store.dispatch('element/select', {
|
2025-02-05 10:44:06 +01:00
|
|
|
builder: currentBuilder,
|
2024-05-02 14:25:42 +00:00
|
|
|
element: null,
|
|
|
|
})
|
2024-02-28 20:20:30 +00:00
|
|
|
if (from.params.builderId !== to.params?.builderId) {
|
|
|
|
// When we switch from one application to another we want to logoff the current
|
|
|
|
// user
|
2025-02-05 10:44:06 +01:00
|
|
|
if (currentBuilder) {
|
2024-10-17 15:49:51 +00:00
|
|
|
// We want to reload once only data for this builder next time
|
|
|
|
this.$store.dispatch('application/forceUpdate', {
|
2025-02-05 10:44:06 +01:00
|
|
|
application: currentBuilder,
|
2024-10-17 15:49:51 +00:00
|
|
|
data: { _loadedOnce: false },
|
|
|
|
})
|
2025-02-05 10:44:06 +01:00
|
|
|
this.$store.dispatch('userSourceUser/logoff', {
|
|
|
|
application: currentBuilder,
|
|
|
|
})
|
2024-10-17 15:49:51 +00:00
|
|
|
}
|
2024-02-28 20:20:30 +00:00
|
|
|
}
|
|
|
|
next()
|
|
|
|
},
|
2023-03-17 10:59:23 +00:00
|
|
|
/**
|
|
|
|
* When the user leaves to another page we want to unselect the selected page. This
|
|
|
|
* way it will not be highlighted the left sidebar.
|
|
|
|
*/
|
|
|
|
beforeRouteLeave(to, from, next) {
|
|
|
|
this.$store.dispatch('page/unselect')
|
2025-02-05 10:44:06 +01:00
|
|
|
|
|
|
|
const builder = this.$store.getters['application/get'](
|
|
|
|
parseInt(from.params.builderId)
|
|
|
|
)
|
|
|
|
|
2024-10-17 15:49:51 +00:00
|
|
|
if (builder) {
|
2025-02-24 13:37:09 +01:00
|
|
|
// Unselect previously selected element
|
|
|
|
this.$store.dispatch('element/select', {
|
|
|
|
builder,
|
|
|
|
element: null,
|
|
|
|
})
|
2024-10-17 15:49:51 +00:00
|
|
|
// We want to reload once only data for this builder next time
|
|
|
|
this.$store.dispatch('application/forceUpdate', {
|
|
|
|
application: builder,
|
|
|
|
data: { _loadedOnce: false },
|
|
|
|
})
|
|
|
|
this.$store.dispatch('userSourceUser/logoff', { application: builder })
|
|
|
|
}
|
|
|
|
|
2023-03-17 10:59:23 +00:00
|
|
|
next()
|
|
|
|
},
|
|
|
|
layout: 'app',
|
2024-11-28 08:47:54 +00:00
|
|
|
async asyncData({ store, params, error, $registry, app }) {
|
2023-02-27 14:33:19 +00:00
|
|
|
const builderId = parseInt(params.builderId)
|
|
|
|
const pageId = parseInt(params.pageId)
|
|
|
|
|
2023-03-22 15:24:55 +00:00
|
|
|
const data = { panelWidth: 360 }
|
2023-02-27 14:33:19 +00:00
|
|
|
|
|
|
|
try {
|
2023-08-11 10:02:53 +00:00
|
|
|
const builder = await store.dispatch('application/selectById', builderId)
|
2024-05-02 14:25:42 +00:00
|
|
|
store.dispatch('userSourceUser/setCurrentApplication', {
|
|
|
|
application: builder,
|
|
|
|
})
|
|
|
|
const workspace = await store.dispatch(
|
|
|
|
'workspace/selectById',
|
|
|
|
builder.workspace.id
|
|
|
|
)
|
2023-08-11 10:02:53 +00:00
|
|
|
|
2024-03-21 16:13:59 +00:00
|
|
|
const builderApplicationType = $registry.get(
|
|
|
|
'application',
|
|
|
|
BuilderApplicationType.getType()
|
|
|
|
)
|
|
|
|
|
2023-08-11 10:02:53 +00:00
|
|
|
const page = store.getters['page/getById'](builder, pageId)
|
2023-03-17 10:59:23 +00:00
|
|
|
|
2024-11-28 08:47:54 +00:00
|
|
|
if (page.shared) {
|
|
|
|
return error({
|
|
|
|
statusCode: 404,
|
|
|
|
message: app.i18n.t('pageEditor.pageNotFound'),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
await builderApplicationType.loadExtraData(builder, mode)
|
2024-10-17 15:49:51 +00:00
|
|
|
|
2023-08-11 10:02:53 +00:00
|
|
|
await Promise.all([
|
|
|
|
store.dispatch('dataSource/fetch', {
|
|
|
|
page,
|
|
|
|
}),
|
2025-02-05 10:44:06 +01:00
|
|
|
store.dispatch('element/fetch', { builder, page }),
|
2023-10-18 15:36:12 +00:00
|
|
|
store.dispatch('workflowAction/fetch', { page }),
|
2023-08-11 10:02:53 +00:00
|
|
|
])
|
2023-08-04 14:29:34 +00:00
|
|
|
|
2023-09-21 14:24:02 +00:00
|
|
|
await DataProviderType.initAll($registry.getAll('builderDataProvider'), {
|
|
|
|
builder,
|
|
|
|
page,
|
2024-02-28 20:20:30 +00:00
|
|
|
mode,
|
2023-09-21 14:24:02 +00:00
|
|
|
})
|
2023-08-04 14:29:34 +00:00
|
|
|
|
2023-08-11 10:02:53 +00:00
|
|
|
// And finally select the page to display it
|
|
|
|
await store.dispatch('page/selectById', {
|
|
|
|
builder,
|
|
|
|
pageId,
|
|
|
|
})
|
|
|
|
|
2024-05-02 14:25:42 +00:00
|
|
|
data.workspace = workspace
|
2023-08-11 10:02:53 +00:00
|
|
|
data.builder = builder
|
2024-11-28 08:47:54 +00:00
|
|
|
data.currentPage = page
|
2023-02-27 14:33:19 +00:00
|
|
|
} catch (e) {
|
|
|
|
// In case of a network error we want to fail hard.
|
|
|
|
if (e.response === undefined && !(e instanceof StoreItemLookupError)) {
|
|
|
|
throw e
|
|
|
|
}
|
|
|
|
|
2024-11-28 08:47:54 +00:00
|
|
|
return error({
|
|
|
|
statusCode: 404,
|
|
|
|
message: app.i18n.t('pageEditor.pageNotFound'),
|
|
|
|
})
|
2023-02-27 14:33:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return data
|
|
|
|
},
|
2023-08-11 10:02:53 +00:00
|
|
|
computed: {
|
2023-09-21 14:24:02 +00:00
|
|
|
applicationContext() {
|
|
|
|
return {
|
2025-04-29 16:46:37 +02:00
|
|
|
workspace: this.workspace,
|
2023-09-21 14:24:02 +00:00
|
|
|
builder: this.builder,
|
2024-02-28 20:20:30 +00:00
|
|
|
mode,
|
2023-09-21 14:24:02 +00:00
|
|
|
}
|
|
|
|
},
|
2023-08-11 10:02:53 +00:00
|
|
|
dataSources() {
|
2024-11-28 08:47:54 +00:00
|
|
|
return this.$store.getters['dataSource/getPageDataSources'](
|
|
|
|
this.currentPage
|
|
|
|
)
|
2023-08-11 10:02:53 +00:00
|
|
|
},
|
2024-10-17 15:49:51 +00:00
|
|
|
sharedPage() {
|
|
|
|
return this.$store.getters['page/getSharedPage'](this.builder)
|
|
|
|
},
|
|
|
|
sharedDataSources() {
|
|
|
|
return this.$store.getters['dataSource/getPageDataSources'](
|
|
|
|
this.sharedPage
|
|
|
|
)
|
|
|
|
},
|
2023-10-31 16:29:20 +00:00
|
|
|
dispatchContext() {
|
2024-04-03 13:40:20 +00:00
|
|
|
return DataProviderType.getAllDataSourceDispatchContext(
|
2023-08-11 10:02:53 +00:00
|
|
|
this.$registry.getAll('builderDataProvider'),
|
2024-11-28 08:47:54 +00:00
|
|
|
{ ...this.applicationContext, page: this.currentPage }
|
2023-08-11 10:02:53 +00:00
|
|
|
)
|
|
|
|
},
|
2024-10-17 15:49:51 +00:00
|
|
|
// Separate dispatch context for application level shared data sources
|
|
|
|
// This one doesn't contain the page.
|
|
|
|
applicationDispatchContext() {
|
|
|
|
return DataProviderType.getAllDataSourceDispatchContext(
|
|
|
|
this.$registry.getAll('builderDataProvider'),
|
|
|
|
{ builder: this.builder, mode }
|
|
|
|
)
|
|
|
|
},
|
2023-08-11 10:02:53 +00:00
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
dataSources: {
|
|
|
|
deep: true,
|
|
|
|
/**
|
|
|
|
* Update data source content on data source configuration changes
|
|
|
|
*/
|
|
|
|
handler() {
|
|
|
|
this.$store.dispatch(
|
|
|
|
'dataSourceContent/debouncedFetchPageDataSourceContent',
|
|
|
|
{
|
2024-11-28 08:47:54 +00:00
|
|
|
page: this.currentPage,
|
2023-10-31 16:29:20 +00:00
|
|
|
data: this.dispatchContext,
|
2024-10-03 14:34:29 +00:00
|
|
|
mode: this.mode,
|
2023-08-11 10:02:53 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
2024-10-17 15:49:51 +00:00
|
|
|
sharedDataSources: {
|
|
|
|
deep: true,
|
|
|
|
/**
|
|
|
|
* Update shared data source content on data source configuration changes
|
|
|
|
*/
|
|
|
|
handler() {
|
|
|
|
this.$store.dispatch(
|
|
|
|
'dataSourceContent/debouncedFetchPageDataSourceContent',
|
|
|
|
{
|
|
|
|
page: this.sharedPage,
|
|
|
|
data: this.dispatchContext,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
2023-10-31 16:29:20 +00:00
|
|
|
dispatchContext: {
|
2023-08-11 10:02:53 +00:00
|
|
|
deep: true,
|
|
|
|
/**
|
|
|
|
* Update data source content on backend context changes
|
|
|
|
*/
|
2024-03-01 13:50:13 +00:00
|
|
|
handler(newDispatchContext, oldDispatchContext) {
|
|
|
|
if (!_.isEqual(newDispatchContext, oldDispatchContext)) {
|
|
|
|
this.$store.dispatch(
|
|
|
|
'dataSourceContent/debouncedFetchPageDataSourceContent',
|
|
|
|
{
|
2024-11-28 08:47:54 +00:00
|
|
|
page: this.currentPage,
|
2024-03-01 13:50:13 +00:00
|
|
|
data: newDispatchContext,
|
2024-10-03 14:34:29 +00:00
|
|
|
mode: this.mode,
|
2024-03-01 13:50:13 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2023-08-11 10:02:53 +00:00
|
|
|
},
|
|
|
|
},
|
2024-10-17 15:49:51 +00:00
|
|
|
applicationDispatchContext: {
|
|
|
|
deep: true,
|
|
|
|
/**
|
|
|
|
* Update data source content on backend context changes
|
|
|
|
*/
|
|
|
|
handler(newDispatchContext, oldDispatchContext) {
|
|
|
|
if (!_.isEqual(newDispatchContext, oldDispatchContext)) {
|
|
|
|
this.$store.dispatch(
|
|
|
|
'dataSourceContent/debouncedFetchPageDataSourceContent',
|
|
|
|
{
|
|
|
|
page: this.sharedPage,
|
|
|
|
data: newDispatchContext,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
2023-08-11 10:02:53 +00:00
|
|
|
},
|
2023-02-27 14:33:19 +00:00
|
|
|
}
|
|
|
|
</script>
|