diff --git a/.env.local-dev.example b/.env.local-dev.example index e4a5af113c..065eeca33f 100644 --- a/.env.local-dev.example +++ b/.env.local-dev.example @@ -51,9 +51,11 @@ SYNC_TEMPLATES_ON_STARTUP=false MIGRATE_ON_STARTUP=false # ============================================================================= -# Optional: Email (use console backend for local dev) +# Email (mailhog via Docker - intercepts all emails) # ============================================================================= -# EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend +# Mailhog web UI: http://localhost:8025 +EMAIL_HOST=localhost +EMAIL_PORT=1025 # ============================================================================= # Optional: Celery diff --git a/.gitignore b/.gitignore index c7bcd7646a..ecb13560ba 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ typings/ # nuxt.js build output .nuxt +.nuxtrc # Nuxt generate dist diff --git a/backend/src/baserow/config/settings/dev.py b/backend/src/baserow/config/settings/dev.py index c71b5ed367..db3b3c4434 100755 --- a/backend/src/baserow/config/settings/dev.py +++ b/backend/src/baserow/config/settings/dev.py @@ -57,8 +57,9 @@ CELERY_EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" EMAIL_USE_TLS = False -EMAIL_HOST = "mailhog" -EMAIL_PORT = 1025 +# Use localhost for local dev (just dev up), mailhog for docker dev (just dc-dev up) +EMAIL_HOST = os.getenv("EMAIL_HOST", "mailhog") +EMAIL_PORT = int(os.getenv("EMAIL_PORT", "1025")) BASEROW_MAX_ROW_REPORT_ERROR_COUNT = 10 # To trigger this exception easily diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index f76b05d5ca..43445b4eec 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -20,6 +20,9 @@ services: caddy: volumes: - $PWD/Caddyfile.dev:/etc/caddy/Caddyfile + # For local development, mount the local backend/media folder so Caddy can + # serve files uploaded by the native backend process. + - $PWD/backend/media:/baserow/media backend: image: baserow_backend:dev @@ -192,6 +195,7 @@ services: logging: driver: "none" # disable saving logs ports: + - "${HOST_PUBLISH_IP:-127.0.0.1}:1025:1025" # smtp - "8025:8025" # web ui networks: local: diff --git a/enterprise/web-frontend/modules/baserow_enterprise/module.js b/enterprise/web-frontend/modules/baserow_enterprise/module.js index 5ff3b05bf4..b278ecc851 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/module.js +++ b/enterprise/web-frontend/modules/baserow_enterprise/module.js @@ -6,25 +6,7 @@ import { extendPages, } from 'nuxt/kit' import { routes, rootChildRoutes } from './routes' - -import en from './locales/en.json' -import fr from './locales/fr.json' -import nl from './locales/nl.json' -import de from './locales/de.json' -import es from './locales/es.json' -import it from './locales/it.json' -import pl from './locales/pl.json' -import ko from './locales/ko.json' - -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, -] +import { locales } from '../../../../web-frontend/config/locales.js' export default defineNuxtModule({ meta: { @@ -65,8 +47,15 @@ export default defineNuxtModule({ } }) - // Add top-level routes (login pages, etc.) - pages.push(...routes) + // Add login pages as children of login-pages (inherit login layout) + const loginPagesRoute = pages.find((route) => route.name === 'login-pages') + if (loginPagesRoute) { + routes.forEach((route) => { + if (!loginPagesRoute.children.find(({ name }) => name === route.name)) { + loginPagesRoute.children.push(route) + } + }) + } }) nuxt.hook('i18n:registerModule', (register) => { diff --git a/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginError.vue b/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginError.vue index 2de0f30770..204488c355 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginError.vue +++ b/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginError.vue @@ -26,24 +26,30 @@ - diff --git a/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginWithSAML.vue b/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginWithSAML.vue index 2af025caf6..bf34b223bd 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginWithSAML.vue +++ b/enterprise/web-frontend/modules/baserow_enterprise/pages/login/loginWithSAML.vue @@ -20,14 +20,14 @@ class="mb-24" > - diff --git a/enterprise/web-frontend/modules/baserow_enterprise/routes.js b/enterprise/web-frontend/modules/baserow_enterprise/routes.js index a4bbad331a..85b527efa8 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/routes.js +++ b/enterprise/web-frontend/modules/baserow_enterprise/routes.js @@ -19,7 +19,7 @@ export const rootChildRoutes = [ }, ] -// Routes at the top level (login pages, etc.) +// Login pages (children of login-pages route, inherit login layout) export const routes = [ { name: 'login-saml', diff --git a/premium/web-frontend/modules/baserow_premium/module.js b/premium/web-frontend/modules/baserow_premium/module.js index 8538b851e5..e1fc8e5dc2 100644 --- a/premium/web-frontend/modules/baserow_premium/module.js +++ b/premium/web-frontend/modules/baserow_premium/module.js @@ -5,25 +5,7 @@ import { extendPages, } from 'nuxt/kit' import { routes } from './routes' - -/*import en from './locales/en.json' -import fr from './locales/fr.json' -import nl from './locales/nl.json' -import de from './locales/de.json' -import es from './locales/es.json' -import it from './locales/it.json' -import pl from './locales/pl.json' -import ko from './locales/ko.json'*/ - -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, -] +import { locales } from '../../../../web-frontend/config/locales.js' export default defineNuxtModule({ meta: { diff --git a/premium/web-frontend/modules/baserow_premium/pages/admin/license.vue b/premium/web-frontend/modules/baserow_premium/pages/admin/license.vue index 6a5e519418..89df94d4f6 100644 --- a/premium/web-frontend/modules/baserow_premium/pages/admin/license.vue +++ b/premium/web-frontend/modules/baserow_premium/pages/admin/license.vue @@ -1,6 +1,6 @@ - - diff --git a/web-frontend/config/locales.js b/web-frontend/config/locales.js new file mode 100644 index 0000000000..85829d3784 --- /dev/null +++ b/web-frontend/config/locales.js @@ -0,0 +1,18 @@ +/** + * Shared locales configuration for all Baserow modules. + * This is the single source of truth for supported languages. + * + * To add a new language: + * 1. Add the locale entry here + * 2. Create the corresponding .json translation files in each module's locales/ directory + */ +export const locales = [ + { code: 'en', name: 'English', file: 'en.json' }, + { code: 'fr', name: 'Français', file: 'fr.json' }, + { code: 'nl', name: 'Nederlands', file: 'nl.json' }, + { code: 'de', name: 'Deutsch', file: 'de.json' }, + { code: 'es', name: 'Español', file: 'es.json' }, + { code: 'it', name: 'Italiano', file: 'it.json' }, + { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, + { code: 'ko', name: '한국어', file: 'ko.json' }, +] diff --git a/web-frontend/config/nuxt.config.base.ts b/web-frontend/config/nuxt.config.base.ts index 37e2a919b8..c7ffb48e97 100644 --- a/web-frontend/config/nuxt.config.base.ts +++ b/web-frontend/config/nuxt.config.base.ts @@ -2,6 +2,7 @@ import path from 'node:path' import { defineNuxtConfig } from 'nuxt/config' import svgLoader from 'vite-svg-loader' import { nodePolyfills } from 'vite-plugin-node-polyfills' +import { locales } from './locales.js' function baserowModuleConfig( premiumBase = '../premium/web-frontend', @@ -49,16 +50,6 @@ function baserowModuleConfig( const baserow = baserowModuleConfig() -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, -] - export default defineNuxtConfig({ compatibilityDate: '2025-07-15', alias: { @@ -100,6 +91,13 @@ export default defineNuxtConfig({ ssr: { noExternal: ['vue-chartjs', 'chart.js'], }, + server: { + sourcemapIgnoreList: (sourcePath) => sourcePath.includes('node_modules'), + }, + optimizeDeps: { + // Pre-bundle moment-guess to avoid missing source map warning + include: ['moment-guess'], + }, }, buildDir: process.env.NUXT_BUILD_DIR || '.nuxt', build: { diff --git a/web-frontend/config/nuxt.config.test.ts b/web-frontend/config/nuxt.config.test.ts index cff5a15393..138cc19408 100644 --- a/web-frontend/config/nuxt.config.test.ts +++ b/web-frontend/config/nuxt.config.test.ts @@ -1,6 +1,26 @@ +/** + * Test Nuxt configuration + * + * We use a direct import rather than `extends: ['./nuxt.config.base.ts']` because + * Nuxt 3's `extends` mechanism is designed for Nuxt layers (directories containing + * their own nuxt.config.ts, app.vue, pages/, etc.), not for importing individual + * config files directly. + * + * When pointing `extends` to a .ts file, Nuxt shows: + * "WARN Cannot extend config from ./nuxt.config.base.ts" + * + * By using a standard ES module import and defu merge, we achieve the same result reliably. + */ import { defineNuxtConfig } from 'nuxt/config' +import defu from 'defu' +import baseConfig from './nuxt.config.base.ts' -export default defineNuxtConfig({ - extends: ['./config/nuxt.config.base.ts'], - modules: ['@nuxt/test-utils/module'], -}) +export default defineNuxtConfig( + defu( + { + // Test-specific configuration + modules: ['@nuxt/test-utils/module'], + }, + baseConfig + ) +) diff --git a/web-frontend/docker/docker-entrypoint.sh b/web-frontend/docker/docker-entrypoint.sh index 5675092ab2..1ebfac25b4 100755 --- a/web-frontend/docker/docker-entrypoint.sh +++ b/web-frontend/docker/docker-entrypoint.sh @@ -14,6 +14,7 @@ nuxt-dev : Start a normal nuxt development server nuxt-dev-with-storybook : Start nuxt dev + storybook in parallel nuxt : Start a non-dev prod ready nuxt server nuxt-local : Start a non-dev prod ready nuxt server using the preset local config +nuxt-prepare : Prepare nuxt (generate .nuxt directory) storybook-dev : Start a storybook dev server bash : Start a bash shell build-local : Triggers a nuxt re-build of Baserow's web-frontend. @@ -96,6 +97,10 @@ case "$1" in setup_additional_modules exec ./node_modules/.bin/nuxt start --hostname "${BASEROW_WEBFRONTEND_BIND_ADDRESS:-0.0.0.0}" --port "$BASEROW_WEBFRONTEND_PORT" --config-file ./config/nuxt.config.local.ts "${@:2}" ;; + nuxt-prepare) + setup_additional_modules + exec ./node_modules/.bin/nuxt prepare "${@:2}" + ;; nuxt-dev-with-storybook) startup_plugin_setup setup_additional_modules diff --git a/web-frontend/modules/automation/module.js b/web-frontend/modules/automation/module.js index 0c8ba8d686..4780193bc9 100644 --- a/web-frontend/modules/automation/module.js +++ b/web-frontend/modules/automation/module.js @@ -5,17 +5,7 @@ import { extendPages, } from 'nuxt/kit' import { routes } from './routes' - -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, - { code: 'ko', name: '한국어', file: 'ko.json' }, -] +import { locales } from '../../config/locales.js' export default defineNuxtModule({ meta: { diff --git a/web-frontend/modules/builder/module.js b/web-frontend/modules/builder/module.js index a87c021071..771c197a66 100644 --- a/web-frontend/modules/builder/module.js +++ b/web-frontend/modules/builder/module.js @@ -7,17 +7,7 @@ import { addRouteMiddleware, } from 'nuxt/kit' import { routes } from './routes' - -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, - { code: 'ko', name: '한국어', file: 'ko.json' }, -] +import { locales } from '../../config/locales.js' export default defineNuxtModule({ meta: { diff --git a/web-frontend/modules/core/components/auth/Login.vue b/web-frontend/modules/core/components/auth/Login.vue index 7670a757b5..3b13d12d95 100644 --- a/web-frontend/modules/core/components/auth/Login.vue +++ b/web-frontend/modules/core/components/auth/Login.vue @@ -53,6 +53,7 @@ settings.allow_reset_password && !passwordLoginHidden " @success="success" + @invitation-accepted="invitationAccepted" @two-factor-auth="setTwoFactorRequired" @email-not-verified="emailNotVerified" /> @@ -184,6 +185,21 @@ export default { } this.$emit('success') }, + async invitationAccepted(workspace) { + if (this.redirectOnSuccess) { + // Clear workspace loaded state so it gets refetched on next page + this.$store.commit('workspace/SET_LOADED', false) + this.$store.commit('application/SET_LOADED', false) + // Redirect to the specific workspace + await this.$router.push({ + name: 'workspace', + params: { workspaceId: workspace.id }, + }) + await pageFinished() + await nextTick() + } + this.$emit('success') + }, emailNotVerified(email) { this.displayEmailNotVerified = true this.emailToVerify = email diff --git a/web-frontend/modules/core/components/auth/PasswordLogin.vue b/web-frontend/modules/core/components/auth/PasswordLogin.vue index 8bd1a9aaaa..031a1e188f 100644 --- a/web-frontend/modules/core/components/auth/PasswordLogin.vue +++ b/web-frontend/modules/core/components/auth/PasswordLogin.vue @@ -2,17 +2,14 @@
- {{ $t('invitationMessage').replace('{invitedBy}', - `${invitation.invited_by}`).replace('{workspace}', - `${invitation.workspace}`) }} - +
@@ -116,7 +113,7 @@ export default { default: true, }, }, - emits: ['email-not-verified', 'success', 'two-factor-auth'], + emits: ['email-not-verified', 'success', 'two-factor-auth', 'invitation-accepted'], setup() { const values = reactive({ values: { @@ -212,13 +209,19 @@ export default { // If there is an invitation we can immediately accept that one after the user // successfully signs in. + let acceptedWorkspace = null if (this.invitation?.email === this.values.email) { - await WorkspaceService(this.$client).acceptInvitation( - this.invitation.id - ) + const { data: workspace } = await WorkspaceService( + this.$client + ).acceptInvitation(this.invitation.id) + acceptedWorkspace = workspace } this.$i18n.setLocale(data.language) - this.$emit('success') + if (acceptedWorkspace) { + this.$emit('invitation-accepted', acceptedWorkspace) + } else { + this.$emit('success') + } } catch (error) { if (error.handler) { const response = error.handler.response diff --git a/web-frontend/modules/core/components/sidebar/SidebarUserContext.vue b/web-frontend/modules/core/components/sidebar/SidebarUserContext.vue index 2fd9e596ff..93f283942e 100644 --- a/web-frontend/modules/core/components/sidebar/SidebarUserContext.vue +++ b/web-frontend/modules/core/components/sidebar/SidebarUserContext.vue @@ -49,7 +49,7 @@
-
  • +
  • { - // Fetch login options (will populate Vuex store) - await store.dispatch('authProvider/fetchLoginOptions') - // Logic from workspaceInvitationToken mixin - const token = route.query.workspaceInvitationToken - let invitation = null - if (token) { - try { - const { data } = await WorkspaceService( - app.$client - ).fetchInvitationByToken(token) - invitation = data - } catch {} +// Data fetching - use token in key to avoid caching issues +const invitationToken = route.query.workspaceInvitationToken +const { data } = await useAsyncData( + `loginData-${invitationToken || 'none'}`, + async () => { + // Fetch login options (will populate Vuex store) + await store.dispatch('authProvider/fetchLoginOptions') + // Logic from workspaceInvitationToken mixin + let invitation = null + if (invitationToken) { + try { + const { data } = await WorkspaceService( + app.$client + ).fetchInvitationByToken(invitationToken) + invitation = data + } catch {} + } + return { invitation } } - return { invitation } -}) +) // Head useHead({ diff --git a/web-frontend/modules/core/pages/signup.vue b/web-frontend/modules/core/pages/signup.vue index f0af7591ea..546b1f9b19 100644 --- a/web-frontend/modules/core/pages/signup.vue +++ b/web-frontend/modules/core/pages/signup.vue @@ -88,8 +88,9 @@ const displayEmailNotVerified = ref(false) const emailToVerify = ref(null) // Fetch invitation data based on token +const invitationToken = route.query.workspaceInvitationToken const { data: invitation } = await useAsyncData( - 'workspace-invitation', + `signup-invitation-${invitationToken || 'none'}`, async () => { // Redirect if already authenticated if (store.getters['auth/isAuthenticated']) { @@ -101,11 +102,10 @@ const { data: invitation } = await useAsyncData( await store.dispatch('authProvider/fetchLoginOptions') // Fetch workspace invitation if token exists - const token = route.query.workspaceInvitationToken - if (token) { + if (invitationToken) { try { const { data } = - await WorkspaceService($client).fetchInvitationByToken(token) + await WorkspaceService($client).fetchInvitationByToken(invitationToken) return data } catch { return null diff --git a/web-frontend/modules/core/pages/workspace.vue b/web-frontend/modules/core/pages/workspace.vue index e5a7a8cbac..0c5bb74b79 100644 --- a/web-frontend/modules/core/pages/workspace.vue +++ b/web-frontend/modules/core/pages/workspace.vue @@ -229,7 +229,12 @@ import DashboardVerifyEmail from '@baserow/modules/core/components/dashboard/Das import TemplateModal from '@baserow/modules/core/components/template/TemplateModal' import DashboardHelp from '@baserow/modules/core/components/dashboard/DashboardHelp' -definePageMeta({ layout: 'app' }) +definePageMeta({ + layout: 'app', + // Note: these middlewares must be explicitly listed because child pages + // don't automatically inherit parent middleware in Nuxt 3's page meta + middleware: ['authenticated', 'workspacesAndApplications', 'impersonate'], +}) defineOptions({ mixins: [editWorkspace], diff --git a/web-frontend/modules/core/pages/workspaceInvitation.vue b/web-frontend/modules/core/pages/workspaceInvitation.vue index 8777b41e8b..b79b6e4e94 100644 --- a/web-frontend/modules/core/pages/workspaceInvitation.vue +++ b/web-frontend/modules/core/pages/workspaceInvitation.vue @@ -1,35 +1,72 @@ - diff --git a/web-frontend/modules/core/store/auth.js b/web-frontend/modules/core/store/auth.js index be821c67bf..b1ae0f7861 100644 --- a/web-frontend/modules/core/store/auth.js +++ b/web-frontend/modules/core/store/auth.js @@ -140,7 +140,7 @@ export const actions = { * Authenticate a user by his email and password. */ async login({ getters, dispatch }, { email, password }) { - const { data } = await AuthService(useNuxtApp().$client).login( + const { data } = await AuthService(this.$client).login( email, password ) @@ -181,7 +181,7 @@ export const actions = { templateId = null, } ) { - const { data } = await AuthService(useNuxtApp().$client).register( + const { data } = await AuthService(this.$client).register( email, name, password, @@ -203,13 +203,14 @@ export const actions = { */ logoff({ getters, dispatch }, { invalidateToken = false }) { const refreshToken = getters.refreshToken + const $client = this.$client dispatch('forceLogoff') if (invalidateToken) { // Invalidate the token async because we don't have to wait for that. setTimeout(() => { - AuthService(useNuxtApp().$client).blacklistToken(refreshToken) + AuthService($client).blacklistToken(refreshToken) }) } }, @@ -277,7 +278,7 @@ export const actions = { * Updates the account information is the authenticated user. */ async update({ getters, commit, dispatch }, values) { - const { data } = await AuthService(useNuxtApp().$client).update(values) + const { data } = await AuthService(this.$client).update(values) dispatch('forceUpdateUserData', { user: data }) dispatch( 'workspace/forceUpdateWorkspaceUserAttributes', @@ -321,7 +322,7 @@ export const actions = { commit('SET_USER_SESSION_EXPIRED', value) }, async fetchWorkspaceInvitations({ commit }) { - const { data } = await AuthService(useNuxtApp().$client).dashboard() + const { data } = await AuthService(this.$client).dashboard() commit('SET_WORKSPACE_INVIATIONS', data.workspace_invitations) return data.workspace_invitations }, @@ -330,7 +331,7 @@ export const actions = { }, async acceptWorkspaceInvitation({ commit }, invitationId) { const { data: workspace } = await WorkspaceService( - useNuxtApp().$client + this.$client ).acceptInvitation(invitationId) commit('REMOVE_WORKSPACE_INVITATION', invitationId) return workspace @@ -339,7 +340,7 @@ export const actions = { commit('REMOVE_WORKSPACE_INVITATION', invitation.id) }, async rejectWorkspaceInvitation({ commit }, invitationId) { - await WorkspaceService(useNuxtApp().$client).rejectInvitation(invitationId) + await WorkspaceService(this.$client).rejectInvitation(invitationId) commit('REMOVE_WORKSPACE_INVITATION', invitationId) }, forceRejectWorkspaceInvitation({ commit }, invitation) { diff --git a/web-frontend/modules/dashboard/module.js b/web-frontend/modules/dashboard/module.js index 20fbe74147..88894f12ec 100644 --- a/web-frontend/modules/dashboard/module.js +++ b/web-frontend/modules/dashboard/module.js @@ -39,16 +39,7 @@ import { extendPages, } from 'nuxt/kit' import { routes } from './routes' - -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, -] +import { locales } from '../../config/locales.js' export default defineNuxtModule({ meta: { diff --git a/web-frontend/modules/database/locales/ko.json b/web-frontend/modules/database/locales/ko.json index f15b175aee..11fabdf57c 100644 --- a/web-frontend/modules/database/locales/ko.json +++ b/web-frontend/modules/database/locales/ko.json @@ -146,7 +146,7 @@ "userFieldNames": "`user_field_names` GET 매개변수를 제공하고 그 값이 다음 중 하나인 경우: `y`, `yes`, `true`, `t`, `on`, `1`, 또는 빈 문자열인 경우, 이 엔드포인트에서 반환되는 필드 이름은 실제 필드 이름이 됩니다.\n\n`user_field_names` GET 매개변수가 제공되지 않거나 위의 값 중 어느 것도 일치하지 않는 경우, 반환되는 모든 필드 이름은 `field_` 뒤에 필드의 ID가 옵니다. 예를 들어 `field_1`은 ID가 `1`인 필드를 나타냅니다.\n\n 또한 `user_field_names`가 설정되면 다른 GET 매개변수 `order_by`, `include` 및 `exclude`의 동작이 변경됩니다. 대신 실제 필드 이름의 쉼표로 구분된 목록을 기대합니다.", "search": "제공된 경우 검색 쿼리와 일치하는 데이터가 있는 행만 반환됩니다.", "orderBy": "선택적으로 쉼표로 구분된 필드로 행을 정렬할 수 있습니다. 기본적으로 또는 '+'가 앞에 오면 필드는 오름차순(A-Z)으로 정렬되지만, '-'가 앞에 오면 내림차순(Z-A)으로 정렬할 수 있습니다.\n\n #### `user_field_names` 사용 시:\n\n `order_by`는 정렬할 필드 이름의 쉼표로 구분된 목록이어야 합니다. 예를 들어 `order_by=My Field,-My Field 2` GET 매개변수를 제공하면 행은 `My Field`라는 필드로 오름차순으로 정렬됩니다. 일부 필드에 동일한 값이 있는 경우 해당 하위 집합은 `My Field 2`라는 필드로 내림차순으로 정렬됩니다.\n\n `+` 또는 `-`로 시작하는 필드 이름은 명시적으로 다른 `+` 또는 `-`를 앞에 붙여야 합니다. 예: `+-Name`.\n\n 쉼표를 포함하는 필드 이름은 따옴표로 묶어야 합니다: `\"Name ,\"`. 필드 이름에 따옴표가 포함된 경우 `\\` 문자를 사용하여 이스케이프해야 합니다. 예: `Name \\\"`.\n\n#### `user_field_names` 없이:\n\n `order_by`는 정렬할 필드의 ID 뒤에 `field_`가 오는 쉼표로 구분된 목록이어야 합니다. 예를 들어 `order_by=field_1,-field_2` GET 매개변수를 제공하면 행은 `field_1`로 오름차순으로 정렬됩니다. 일부 필드에 동일한 값이 있는 경우 해당 하위 집합은 `field_2`로 내림차순으로 정렬됩니다.", - "filters": "행은 선택적으로 뷰에 사용할 수 있는 동일한 뷰 필터를 사용하여 필터링할 수 있습니다. 이 매개변수는 이 뷰에 적용할 필터 트리를 포함하는 JSON 직렬화된 문자열을 허용합니다. 필터 트리는 적용해야 하는 필터를 포함하는 중첩된 구조입니다. \n\n#### `user_field_names` 사용 시:\n\n유효한 필터 트리의 예는 다음과 같습니다: `{'{'{'}'}{'{'{'}'}'filter_type': 'AND', 'filters': [{'{'{'}'}{'{'{'}'}'field': 'Name', 'type': 'equal', 'value': 'test'{'}'}{'}'}]{'}'}{'}'}`.\n\n#### `user_field_names` 없이:\n\n예를 들어 다음 GET 매개변수를 제공하는 경우: `{'{'{'}'}{'{'{'}'}'filter_type': 'AND', 'filters': [{'{'{'}'}{'{'{'}'}'field': 1, 'type': 'equal', 'value': 'test'{'}'}{'}'}]{'}'}{'}'}`\n\n이 매개변수가 제공된 경우, 모든 다른 `filter__{field}__{filter}`는 무시되며, filter_type 매개변수도 무시됩니다.", + "filters": "행은 선택적으로 뷰에 사용할 수 있는 동일한 뷰 필터를 사용하여 필터링할 수 있습니다. 이 매개변수는 이 뷰에 적용할 필터 트리를 포함하는 JSON 직렬화된 문자열을 허용합니다. 필터 트리는 적용해야 하는 필터를 포함하는 중첩된 구조입니다. \n\n#### `user_field_names` 사용 시:\n\n유효한 필터 트리의 예는 다음과 같습니다: `{'{'}\"filter_type\": \"AND\", \"filters\": [{'{'}\"field\": \"Name\", \"type\": \"equal\", \"value\": \"test\"{'}'}]{'}'}`.\n\n#### `user_field_names` 없이:\n\n예를 들어 다음 GET 매개변수를 제공하는 경우: `{'{'}\"filter_type\": \"AND\", \"filters\": [{'{'}\"field\": 1, \"type\": \"equal\", \"value\": \"test\"{'}'}]{'}'}`\n\n이 매개변수가 제공된 경우, 모든 다른 `filter__{'{'}field{'}'}__{'{'}filter{'}'}` 는 무시되며, filter_type 매개변수도 무시됩니다.", "filter": "행은 선택적으로 뷰에 사용할 수 있는 동일한 뷰 필터를 사용하여 필터링할 수 있습니다. 동일한 형식을 따르는 경우 여러 필터를 적용할 수 있습니다. `field` 및 `filter` 변수는 각각 필터를 적용할 방법과 위치를 나타냅니다.\n\n#### `user_field_names` 사용 시:\n\n예를 들어 다음 GET 매개변수를 제공하는 경우: `filter__Name__equal=test`, `Name`의 값이 'test'인 행만 반환됩니다. 이 방법은 이전 버전과 호환되며 이름에서 실패하면 `field_id`를 확인합니다.\n\n#### `user_field_names` 없이:\n\n예를 들어 다음 GET 매개변수를 제공하는 경우: `filter__field_1__equal=test`, `field_1`의 값이 'test'인 행만 반환됩니다.\n\n필터 매개변수가 제공된 경우 이 매개변수는 무시됩니다. ", "filterLink": "모든 필터 목록은 여기에서 찾을 수 있습니다.", "filterType": "- `AND`: 제공된 모든 필터와 일치해야 함을 나타냅니다.\n- `OR`: 필터 중 하나와만 일치하면 됨을 나타냅니다.\n\n 이는 두 개 이상의 필터가 제공된 경우에만 작동합니다.", diff --git a/web-frontend/modules/database/module.js b/web-frontend/modules/database/module.js index df78fd22c9..4c427a204f 100644 --- a/web-frontend/modules/database/module.js +++ b/web-frontend/modules/database/module.js @@ -39,16 +39,7 @@ import { extendPages, } from 'nuxt/kit' import { routes } from './routes' - -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, -] +import { locales } from '../../config/locales.js' export default defineNuxtModule({ meta: { diff --git a/web-frontend/modules/integrations/module.js b/web-frontend/modules/integrations/module.js index 061067f931..b272f1ed1e 100644 --- a/web-frontend/modules/integrations/module.js +++ b/web-frontend/modules/integrations/module.js @@ -1,15 +1,5 @@ import { defineNuxtModule, addPlugin, createResolver } from 'nuxt/kit' - -const locales = [ - { code: 'en', name: 'English', file: 'en.json' }, - { code: 'fr', name: 'Français', file: 'fr.json' }, - { code: 'nl', name: 'Nederlands', file: 'nl.json' }, - { code: 'de', name: 'Deutsch', file: 'de.json' }, - { code: 'es', name: 'Español', file: 'es.json' }, - { code: 'it', name: 'Italiano', file: 'it.json' }, - { code: 'pl', name: 'Polski (Beta)', file: 'pl.json' }, - { code: 'ko', name: '한국어', file: 'ko.json' }, -] +import { locales } from '../../config/locales.js' export default defineNuxtModule({ meta: {