diff --git a/web-frontend/modules/automation/locales/en.json b/web-frontend/modules/automation/locales/en.json index 767e6b5a6d..3fc5aecae9 100644 --- a/web-frontend/modules/automation/locales/en.json +++ b/web-frontend/modules/automation/locales/en.json @@ -158,29 +158,6 @@ "coreHTTPTrigger": "HTTP trigger", "coreHTTPTriggerDescription": "Receive HTTP requests to trigger workflows" }, - "periodicTriggerServiceForm": { - "intervalLabel": "Interval", - "intervalHelper": "Choose how frequently you want this workflow to run", - "everyMinute": "Every minute", - "everyHour": "Every hour", - "everyDay": "Every day", - "everyWeek": "Every week", - "everyMonth": "Every month", - "hour": "Hour", - "minute": "Minute", - "dayOfWeek": "Day of week", - "dayOfMonth": "Day of month", - "hourPlaceholder": "0-23", - "minutePlaceholder": "0-59", - "dayOfMonthPlaceholder": "1-31", - "minuteHelper": "This workflow will run every minute", - "hourHelper": "This workflow will run every hour at the specified minute in your local timezone ({timezone})", - "dayHelper": "This workflow will run every day at the specified time in your local timezone ({timezone})", - "weekHelper": "This workflow will run every week on the specified day and time in your local timezone ({timezone})", - "monthHelper": "This workflow will run every month on the specified day and time in your local timezone ({timezone})", - "deactivatedTitle": "Periodic trigger deactivated", - "deactivatedText": "This periodic trigger has been automatically deactivated due to consecutive failures." - }, "workflowEditor": { "chooseEvent": "Choose an event..." }, diff --git a/web-frontend/modules/automation/plugin.js b/web-frontend/modules/automation/plugin.js index 651200d327..f084201d5b 100644 --- a/web-frontend/modules/automation/plugin.js +++ b/web-frontend/modules/automation/plugin.js @@ -45,6 +45,7 @@ import { } from '@baserow/modules/automation/dataProviderTypes' export default defineNuxtPlugin({ + name: 'automation', dependsOn: ['core', 'store'], setup(nuxtApp) { const { $registry, $store, $clientErrorMap, $i18n } = nuxtApp diff --git a/web-frontend/modules/builder/components/page/header/DataSourceContext.vue b/web-frontend/modules/builder/components/page/header/DataSourceContext.vue index e9406a7063..e82d1054c2 100644 --- a/web-frontend/modules/builder/components/page/header/DataSourceContext.vue +++ b/web-frontend/modules/builder/components/page/header/DataSourceContext.vue @@ -112,7 +112,6 @@ ({ })) // Load page data -const { - data: pageData, - error: pageError, - pending: pagePending, - refresh: refreshPage, -} = await useAsyncData( +const { data: pageData, error: pageError } = await useAsyncData( () => `page-editor-${route.params.builderId}-${route.params.pageId}`, async () => { // The objects are selected by the middleware @@ -103,10 +98,14 @@ const { mode, }) + const sharedPage = + await $store.getters['page/getSharedPage'](loadedBuilder) + return { workspace: loadedWorkspace, builder: loadedBuilder, page, + sharedPage, } } catch (e) { if (e.response === undefined && !(e instanceof StoreItemLookupError)) { @@ -121,21 +120,24 @@ const { } ) +if (pageError.value) { + // If we have an error we want to display it. + throw pageError.value +} + const workspace = computed(() => pageData.value?.workspace ?? null) const builder = computed(() => pageData.value?.builder ?? null) const currentPage = computed(() => pageData.value?.page ?? null) +const sharedPage = computed(() => pageData.value?.sharedPage ?? null) // Computed properties const dataSources = computed(() => { + if (!currentPage.value) return [] return $store.getters['dataSource/getPageDataSources'](currentPage.value) }) -const sharedPage = computed(() => { - if (!builder.value) return null - return $store.getters['page/getSharedPage'](builder.value) -}) - const sharedDataSources = computed(() => { + if (!sharedPage.value) return [] return $store.getters['dataSource/getPageDataSources'](sharedPage.value) }) diff --git a/web-frontend/modules/builder/plugins/router.js b/web-frontend/modules/builder/plugins/router.js index 1d4b90abaa..475bdbe5ee 100644 --- a/web-frontend/modules/builder/plugins/router.js +++ b/web-frontend/modules/builder/plugins/router.js @@ -3,28 +3,24 @@ */ export default defineNuxtPlugin({ name: 'router', - dependsOn: ['core', 'builder', 'database'], - setup() { - const router = useRouter() - const runtimeConfig = useRuntimeConfig() - - // SSR-safe host detection - const requestHostname = useRequestURL().hostname - - const frontendHostname = new URL(runtimeConfig.public.publicWebFrontendUrl) - .hostname + dependsOn: [ + 'is-web-frontend-hostname', + 'core', + 'builder', + 'database', + 'automation', + 'dashboard', + // Should execute after other applications are loaded to remove all the + // unnecessary routes + ], - const extraPublicHostnames = - runtimeConfig.public.extraPublicWebFrontendHostnames || [] - - // Check if request hostname matches main hostname or any extra hostname so we know - // whether the tool or a published application must be served. - const isWebFrontendHostname = - frontendHostname === requestHostname || - extraPublicHostnames.includes(requestHostname) + setup(nuxtApp) { + const router = useRouter() + const { $isWebFrontendHostname } = nuxtApp + // Ensure only published routes are available if this is a published hostname for (const r of router.getRoutes()) { - if (isWebFrontendHostname) { + if ($isWebFrontendHostname) { if (r.meta?.publishedBuilderRoute && router.hasRoute(r.name)) { router.removeRoute(r.name) } diff --git a/web-frontend/modules/builder/utils/routing.js b/web-frontend/modules/builder/utils/routing.js index 9dcc3168f3..4d1b009c85 100644 --- a/web-frontend/modules/builder/utils/routing.js +++ b/web-frontend/modules/builder/utils/routing.js @@ -4,12 +4,10 @@ export const resolveApplicationRoute = (pages, fullPath) => { if (fullPath === undefined || fullPath === null) { return undefined } - // Nuxt route.fullPath usually includes query/hash; path-to-regexp matches pathnames. - const pathname = fullPath.split('?')[0].split('#')[0] for (const page of pages) { const matcher = match(page.path.slice(1)) - const matched = matcher(pathname) + const matched = matcher(fullPath) if (matched) { // matched = { path, params, index? } diff --git a/web-frontend/modules/core/mixins/moveToBody.js b/web-frontend/modules/core/mixins/moveToBody.js index 08b39e3d2b..bc6acb9708 100644 --- a/web-frontend/modules/core/mixins/moveToBody.js +++ b/web-frontend/modules/core/mixins/moveToBody.js @@ -23,19 +23,15 @@ export default { // to prevent closing when clicking in a child. We also check which parent // is first so can correctly move the element. while (parent) { - if (Object.prototype.hasOwnProperty.call(parent, 'moveToBody')) { + if (parent?.$data?.moveToBody) { parent.registerMoveToBodyChild(this) - if (first === null) { - first = parent - } + if (first === null) first = parent } // There could be components that need to know which child element have - // been moved to the body, but haven't moved to the body themself. If they + // been moved to the body, but haven't moved to the body themselves. If they // only have a `registerMoveToBodyChild` method, we register this // component a there. - else if ( - Object.prototype.hasOwnProperty.call(parent, 'registerMoveToBodyChild') - ) { + else if (parent && typeof parent.registerMoveToBodyChild === 'function') { parent.registerMoveToBodyChild(this) } parent = parent.$parent @@ -64,11 +60,9 @@ export default { } } else if (this.$el) { // Because there is no parent we can directly move the component to the - // end of the body. Elements that mount later are appended after earlier - // ones so that they appear on top when sharing the same z-index (DOM - // order determines visual stacking for equal z-index values). + // top of the body so it will be positioned over any other element. const body = document.body - body.appendChild(this.$el) + body.insertBefore(this.$el, body.firstChild) this.fireMovedToBodyHandlers() } diff --git a/web-frontend/modules/core/module.js b/web-frontend/modules/core/module.js index 9d02f327cb..78eb5cfa25 100644 --- a/web-frontend/modules/core/module.js +++ b/web-frontend/modules/core/module.js @@ -135,6 +135,7 @@ export default defineNuxtModule({ //addPlugin(resolve('plugins/router.js')) addPlugin(resolve('plugins/routeMounted.js')) addPlugin(resolve('plugins/storeRegister.js')) + addPlugin(resolve('plugins/isWebFrontendHostname.js')) addRouteMiddleware({ name: 'authentication', diff --git a/web-frontend/modules/core/pages/workspace.vue b/web-frontend/modules/core/pages/workspace.vue index 67648cc6d6..d6aa32abab 100644 --- a/web-frontend/modules/core/pages/workspace.vue +++ b/web-frontend/modules/core/pages/workspace.vue @@ -243,7 +243,6 @@ definePageMeta({ 'impersonate', 'workspacesAndApplications', ], - useRouteWorkspaceParam: 'test', }) defineOptions({ diff --git a/web-frontend/modules/core/plugins/isWebFrontendHostname.js b/web-frontend/modules/core/plugins/isWebFrontendHostname.js new file mode 100644 index 0000000000..fe6565e672 --- /dev/null +++ b/web-frontend/modules/core/plugins/isWebFrontendHostname.js @@ -0,0 +1,26 @@ +/** + * Whether the current hostname is a webfrontend hostname or not... + */ +export default defineNuxtPlugin({ + name: 'is-web-frontend-hostname', + setup() { + const runtimeConfig = useRuntimeConfig() + + // SSR-safe host detection + const requestHostname = useRequestURL().hostname + + const frontendHostname = new URL(runtimeConfig.public.publicWebFrontendUrl) + .hostname + + const extraPublicHostnames = + runtimeConfig.public.extraPublicWebFrontendHostnames || [] + + // Check if request hostname matches main hostname or any extra hostname so we know + // whether the tool or a published application must be served. + const isWebFrontendHostname = + frontendHostname === requestHostname || + extraPublicHostnames.includes(requestHostname) + + return { provide: { isWebFrontendHostname } } + }, +}) diff --git a/web-frontend/modules/core/plugins/realTimeHandler.js b/web-frontend/modules/core/plugins/realTimeHandler.js index e03f54b2e8..f7fc7e9735 100644 --- a/web-frontend/modules/core/plugins/realTimeHandler.js +++ b/web-frontend/modules/core/plugins/realTimeHandler.js @@ -1,6 +1,6 @@ import { isSecureURL } from '@baserow/modules/core/utils/string' import { logoutAndRedirectToLogin } from '@baserow/modules/core/utils/auth' -import { useRouter, useRuntimeConfig } from '#imports' +import { useRuntimeConfig } from '#imports' export class RealTimeHandler { constructor(context) { diff --git a/web-frontend/modules/core/utils/workspace.js b/web-frontend/modules/core/utils/workspace.js index 03adb17f0a..7490d494e1 100644 --- a/web-frontend/modules/core/utils/workspace.js +++ b/web-frontend/modules/core/utils/workspace.js @@ -5,14 +5,7 @@ import { useCookie } from '#app' const cookieWorkspaceName = 'baserow_group_id' export const setWorkspaceCookie = (workspaceId, { $config }) => { - if (import.meta.server) return const secure = isSecureURL($config.public.publicWebFrontendUrl) - /*$cookies.set(cookieWorkspaceName, workspaceId, { - path: '/', - maxAge: 60 * 60 * 24 * 7, - sameSite: $config.BASEROW_FRONTEND_SAME_SITE_COOKIE, - secure, - })*/ const cookie = useCookie(cookieWorkspaceName, { path: '/', maxAge: 60 * 60 * 24 * 7, @@ -23,16 +16,10 @@ export const setWorkspaceCookie = (workspaceId, { $config }) => { } export const unsetWorkspaceCookie = () => { - if (import.meta.server) return const cookie = useCookie(cookieWorkspaceName) cookie.value = null - //deleteCookie(cookieWorkspaceName) - //$cookies.remove(cookieWorkspaceName) } export const getWorkspaceCookie = () => { - if (import.meta.server) return return useCookie(cookieWorkspaceName).value - //return getCookie(cookieWorkspaceName) - //return $cookies.get(cookieWorkspaceName) } diff --git a/web-frontend/modules/dashboard/plugin.js b/web-frontend/modules/dashboard/plugin.js index 1d4f234782..606e86fe74 100644 --- a/web-frontend/modules/dashboard/plugin.js +++ b/web-frontend/modules/dashboard/plugin.js @@ -1,84 +1,16 @@ -// import en from '@baserow/modules/dashboard/locales/en.json' -// import fr from '@baserow/modules/dashboard/locales/fr.json' -// import nl from '@baserow/modules/dashboard/locales/nl.json' -// import de from '@baserow/modules/dashboard/locales/de.json' -// import es from '@baserow/modules/dashboard/locales/es.json' -// import it from '@baserow/modules/dashboard/locales/it.json' -// import pl from '@baserow/modules/dashboard/locales/pl.json' -// import ko from '@baserow/modules/dashboard/locales/ko.json' - -// import { registerRealtimeEvents } from '@baserow/modules/dashboard/realtime' -// import { DashboardApplicationType } from '@baserow/modules/dashboard/applicationTypes' -// import { SummaryWidgetType } from '@baserow/modules/dashboard/widgetTypes' -// import dashboardApplicationStore from '@baserow/modules/dashboard/store/dashboardApplication' -// import { DashboardSearchType } from '@baserow/modules/dashboard/searchTypes' -// import { searchTypeRegistry } from '@baserow/modules/core/search/types/registry' - -// export default (context) => { -// const { app, isDev, store } = context - -// // Allow locale file hot reloading in dev -// if (isDev && app.i18n) { -// const { i18n } = app -// i18n.mergeLocaleMessage('en', en) -// i18n.mergeLocaleMessage('fr', fr) -// i18n.mergeLocaleMessage('nl', nl) -// i18n.mergeLocaleMessage('de', de) -// i18n.mergeLocaleMessage('es', es) -// i18n.mergeLocaleMessage('it', it) -// i18n.mergeLocaleMessage('pl', pl) -// i18n.mergeLocaleMessage('ko', ko) -// } - -// registerRealtimeEvents(app.$realtime) - -// store.registerModule('dashboardApplication', dashboardApplicationStore) -// store.registerModule( -// 'template/dashboardApplication', -// dashboardApplicationStore -// ) - -// app.$registry.register('application', new DashboardApplicationType(context)) -// app.$registry.register('dashboardWidget', new SummaryWidgetType(context)) - -// searchTypeRegistry.register(new DashboardSearchType()) -// } - -import { registerRealtimeEvents } from '@baserow/modules/dashboard/realtime' import { DashboardSearchType } from '@baserow/modules/dashboard/searchTypes' import { searchTypeRegistry } from '@baserow/modules/core/search/types/registry' import dashboardApplicationStore from '@baserow/modules/dashboard/store/dashboardApplication' import { DashboardApplicationType } from '@baserow/modules/dashboard/applicationTypes' import { SummaryWidgetType } from '@baserow/modules/dashboard/widgetTypes' -// Import translations -/*import en from '@baserow/modules/dashboard/locales/en.json' -import fr from '@baserow/modules/dashboard/locales/fr.json' -import nl from '@baserow/modules/dashboard/locales/nl.json' -import de from '@baserow/modules/dashboard/locales/de.json' -import es from '@baserow/modules/dashboard/locales/es.json' -import it from '@baserow/modules/dashboard/locales/it.json' -import pl from '@baserow/modules/dashboard/locales/pl.json' -import ko from '@baserow/modules/dashboard/locales/ko.json'*/ - export default defineNuxtPlugin({ + name: 'dashboard', dependsOn: ['core', 'store'], async setup(nuxtApp) { - const { $store, $registry, $i18n } = nuxtApp + const { $store, $registry } = nuxtApp const context = { app: nuxtApp } - // Merge dashboard translations into i18n - /*if ($i18n) { - $i18n.mergeLocaleMessage('en', en) - $i18n.mergeLocaleMessage('fr', fr) - $i18n.mergeLocaleMessage('nl', nl) - $i18n.mergeLocaleMessage('de', de) - $i18n.mergeLocaleMessage('es', es) - $i18n.mergeLocaleMessage('it', it) - $i18n.mergeLocaleMessage('pl', pl) - $i18n.mergeLocaleMessage('ko', ko) - } */ - if (!$store.hasModule('dashboardApplication')) { $store.registerModuleNuxtSafe( 'dashboardApplication', diff --git a/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap b/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap index 0ea3217dc6..70df5760d6 100644 --- a/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap +++ b/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap @@ -122,12 +122,6 @@ exports[`GridViewRows component with decoration > Should show cant add decorator viewDecoratorType.onlyForPremium -
- -
Should show cant add decorator
+
+ +
`; @@ -252,12 +252,6 @@ exports[`GridViewRows component with decoration > Should show unavailable decora viewDecoratorType.onlyForPremium -
- -
Should show unavailable decora
+
+ +
`;