diff --git a/.nvmrc b/.nvmrc index b6a7d89c6..3c032078a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16 +18 diff --git a/backend/src/baserow/contrib/builder/domains/handler.py b/backend/src/baserow/contrib/builder/domains/handler.py index eb49c8dc8..e593d62fb 100644 --- a/backend/src/baserow/contrib/builder/domains/handler.py +++ b/backend/src/baserow/contrib/builder/domains/handler.py @@ -107,6 +107,10 @@ class DomainHandler: prepared_values = domain_type.prepare_values(allowed_values) + # Save only lower case domain + if "domain_name" in prepared_values: + prepared_values["domain_name"] = prepared_values["domain_name"].lower() + domain = model_class(builder=builder, order=last_order, **prepared_values) domain.save() @@ -138,6 +142,10 @@ class DomainHandler: prepared_values = domain_type.prepare_values(allowed_values) + # Save only lower case domain + if "domain_name" in prepared_values: + prepared_values["domain_name"] = prepared_values["domain_name"].lower() + for key, value in prepared_values.items(): setattr(domain, key, value) diff --git a/backend/src/baserow/contrib/builder/pages/handler.py b/backend/src/baserow/contrib/builder/pages/handler.py index 32bdc4dd7..64a556fbd 100644 --- a/backend/src/baserow/contrib/builder/pages/handler.py +++ b/backend/src/baserow/contrib/builder/pages/handler.py @@ -228,9 +228,13 @@ class PageHandler: :return: A unique path to use """ + page_path = proposed_path + if page_path.endswith("/"): + page_path = page_path[:-1] + existing_paths = list(builder.page_set.values_list("path", flat=True)) return find_unused_name( - [proposed_path], existing_paths, max_length=255, suffix="{0}" + [page_path], existing_paths, max_length=255, suffix="/{0}" ) def is_page_path_valid( diff --git a/backend/tests/baserow/contrib/builder/pages/test_page_handler.py b/backend/tests/baserow/contrib/builder/pages/test_page_handler.py index 07cba1b8f..ac4a98f79 100644 --- a/backend/tests/baserow/contrib/builder/pages/test_page_handler.py +++ b/backend/tests/baserow/contrib/builder/pages/test_page_handler.py @@ -213,7 +213,7 @@ def test_is_page_path_valid_raises(): def test_find_unused_page_path(data_fixture): page = data_fixture.create_builder_page(path="/test") - assert PageHandler().find_unused_page_path(page.builder, "/test") == "/test2" + assert PageHandler().find_unused_page_path(page.builder, "/test") == "/test/2" @pytest.mark.django_db diff --git a/enterprise/web-frontend/modules/baserow_enterprise/integrations/appAuthProviderTypes.js b/enterprise/web-frontend/modules/baserow_enterprise/integrations/appAuthProviderTypes.js index 0d85b6503..19eabf8e3 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/integrations/appAuthProviderTypes.js +++ b/enterprise/web-frontend/modules/baserow_enterprise/integrations/appAuthProviderTypes.js @@ -1,9 +1,6 @@ import { AppAuthProviderType } from '@baserow/modules/core/appAuthProviderTypes' import LocalBaserowUserSourceForm from '@baserow_enterprise/integrations/localBaserow/components/appAuthProviders/LocalBaserowPasswordAppAuthProviderForm' -import { - TextFieldType, - LongTextFieldType, -} from '@baserow/modules/database/fieldTypes' +import { PasswordFieldType } from '@baserow/modules/database/fieldTypes' export class LocalBaserowPasswordAppAuthProviderType extends AppAuthProviderType { static getType() { @@ -23,7 +20,7 @@ export class LocalBaserowPasswordAppAuthProviderType extends AppAuthProviderType * It's defined here so that it can be changed by a plugin. */ get allowedPasswordFieldTypes() { - return [TextFieldType.getType(), LongTextFieldType.getType()] + return [PasswordFieldType.getType()] } getOrder() { diff --git a/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json b/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json index 36531931f..71faf6679 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json +++ b/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json @@ -296,6 +296,7 @@ "localBaserowPassword": "Email/Password" }, "localBaserowPasswordAppAuthProviderForm": { - "passwordFieldLabel": "Select password field" + "passwordFieldLabel": "Select password field", + "noFields": "No compatible fields" } } diff --git a/web-frontend/modules/builder/components/elements/components/HeadingElement.vue b/web-frontend/modules/builder/components/elements/components/HeadingElement.vue index 3c65ac617..c3b76b8f9 100644 --- a/web-frontend/modules/builder/components/elements/components/HeadingElement.vue +++ b/web-frontend/modules/builder/components/elements/components/HeadingElement.vue @@ -8,9 +8,12 @@ <component :is="`h${element.level}`" class="heading-element__heading" - :class="{ [`ab-heading--h${element.level}`]: true }" + :class="`ab-heading--h${element.level}`" :style="{ - '--color': resolveColor(element.font_color, headingColorVariables), + [`--heading-h${element.level}--color`]: resolveColor( + element.font_color, + headingColorVariables + ), }" > {{ resolvedValue || $t('headingElement.noValue') }} diff --git a/web-frontend/modules/builder/components/elements/components/collectionField/form/LinkFieldForm.vue b/web-frontend/modules/builder/components/elements/components/collectionField/form/LinkFieldForm.vue index 83ab6ac7a..c63becb23 100644 --- a/web-frontend/modules/builder/components/elements/components/collectionField/form/LinkFieldForm.vue +++ b/web-frontend/modules/builder/components/elements/components/collectionField/form/LinkFieldForm.vue @@ -48,6 +48,9 @@ :label="$t('linkNavigationSelection.url')" :placeholder="$t('linkNavigationSelection.urlPlaceholder')" :data-providers-allowed="DATA_PROVIDERS_ALLOWED_ELEMENTS" + :application-context-additions="{ + element, + }" /> </FormGroup> diff --git a/web-frontend/modules/builder/components/page/PreviewNavigationBar.vue b/web-frontend/modules/builder/components/page/PreviewNavigationBar.vue index 871d734e5..4eba12bcf 100644 --- a/web-frontend/modules/builder/components/page/PreviewNavigationBar.vue +++ b/web-frontend/modules/builder/components/page/PreviewNavigationBar.vue @@ -23,7 +23,7 @@ /> <div v-else - :key="pathPart.key" + :key="`else_${pathPart.key}`" class="preview-navigation-bar__address-bar-path" > {{ pathPart.value }} diff --git a/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue b/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue index d0c7e1e36..badc87ff0 100644 --- a/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue +++ b/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue @@ -106,15 +106,18 @@ </div> </div> <div class="theme_settings__section-preview"> - <h1 - class="heading-element margin-bottom-2 theme_settings__section-ellipsis" + <component + :is="`h${i}`" + class="margin-bottom-2 theme_settings__section-ellipsis" + :class="`ab-heading--h${i}`" :style="{ - '--color': builder.theme[`heading_${i}_color`], - '--font-size': builder.theme[`heading_${i}_font_size`] + 'px', + [`--heading-h${i}--color`]: builder.theme[`heading_${i}_color`], + [`--heading-h${i}--font-size`]: + builder.theme[`heading_${i}_font_size`] + 'px', }" > {{ $t('mainThemeConfigBlock.headingValue', { i }) }} - </h1> + </component> </div> </div> </div> diff --git a/web-frontend/modules/builder/elementTypes.js b/web-frontend/modules/builder/elementTypes.js index c81e45352..d0663c956 100644 --- a/web-frontend/modules/builder/elementTypes.js +++ b/web-frontend/modules/builder/elementTypes.js @@ -13,7 +13,10 @@ import TableElement from '@baserow/modules/builder/components/elements/component import TableElementForm from '@baserow/modules/builder/components/elements/components/forms/general/TableElementForm' import { ELEMENT_EVENTS } from '@baserow/modules/builder/enums' -import { ensureBoolean } from '@baserow/modules/core/utils/validator' +import { + ensureBoolean, + ensureString, +} from '@baserow/modules/core/utils/validator' import ColumnElement from '@baserow/modules/builder/components/elements/components/ColumnElement' import ColumnElementForm from '@baserow/modules/builder/components/elements/components/forms/general/ColumnElementForm' import _ from 'lodash' @@ -296,11 +299,10 @@ export class FormElementType extends ElementType { */ getDisplayName(element, applicationContext) { if (element.label) { - const resolvedName = this.resolveFormula( - element.label, - applicationContext - ) - return resolvedName.length ? resolvedName : this.name + const resolvedName = ensureString( + this.resolveFormula(element.label, applicationContext) + ).trim() + return resolvedName || this.name } return this.name } @@ -359,9 +361,11 @@ export class InputTextElementType extends FormElementType { const displayValue = element.label || element.default_value || element.placeholder - if (displayValue && displayValue.length) { - const resolvedName = this.resolveFormula(displayValue, applicationContext) - return resolvedName.length ? resolvedName : this.name + if (displayValue?.trim()) { + const resolvedName = ensureString( + this.resolveFormula(displayValue, applicationContext) + ).trim() + return resolvedName || this.name } return this.name } @@ -401,11 +405,10 @@ export class HeadingElementType extends ElementType { getDisplayName(element, applicationContext) { if (element.value && element.value.length) { - const resolvedName = this.resolveFormula( - element.value, - applicationContext - ) - return resolvedName.length ? resolvedName : this.name + const resolvedName = ensureString( + this.resolveFormula(element.value, applicationContext) + ).trim() + return resolvedName || this.name } return this.name } @@ -437,12 +440,11 @@ export class TextElementType extends ElementType { } getDisplayName(element, applicationContext) { - if (element.value && element.value.length) { - const resolvedName = this.resolveFormula( - element.value, - applicationContext - ) - return resolvedName.length ? resolvedName : this.name + if (element.value) { + const resolvedName = ensureString( + this.resolveFormula(element.value, applicationContext) + ).trim() + return resolvedName || this.name } return this.name } @@ -489,10 +491,9 @@ export class LinkElementType extends ElementType { destination = `${destinationPage.name}` } } else if (element.navigation_type === 'custom') { - destination = this.resolveFormula( - element.navigate_to_url, - applicationContext - ) + destination = ensureString( + this.resolveFormula(element.navigate_to_url, applicationContext) + ).trim() } if (destination) { @@ -500,7 +501,9 @@ export class LinkElementType extends ElementType { } if (element.value) { - displayValue = this.resolveFormula(element.value, applicationContext) + displayValue = ensureString( + this.resolveFormula(element.value, applicationContext) + ).trim() } return displayValue @@ -535,12 +538,11 @@ export class ImageElementType extends ElementType { } getDisplayName(element, applicationContext) { - if (element.alt_text && element.alt_text.length) { - const resolvedName = this.resolveFormula( - element.alt_text, - applicationContext - ) - return resolvedName.length ? resolvedName : this.name + if (element.alt_text) { + const resolvedName = ensureString( + this.resolveFormula(element.alt_text, applicationContext) + ).trim() + return resolvedName || this.name } return this.name } @@ -576,12 +578,11 @@ export class ButtonElementType extends ElementType { } getDisplayName(element, applicationContext) { - if (element.value && element.value.length) { - const resolvedName = this.resolveFormula( - element.value, - applicationContext - ) - return resolvedName.length ? resolvedName : this.name + if (element.value) { + const resolvedName = ensureString( + this.resolveFormula(element.value, applicationContext) + ).trim() + return resolvedName || this.name } return this.name } @@ -654,16 +655,17 @@ export class TableElementType extends ElementType { } getDisplayName(element, { page }) { - let displayValue = '' + let suffix = '' + if (element.data_source_id) { const dataSource = this.app.store.getters[ 'dataSource/getPageDataSourceById' ](page, element.data_source_id) - displayValue = dataSource - ? `${dataSource.name} ${this.name.toLowerCase()}` - : '' + + suffix = dataSource ? ` - ${dataSource.name}` : '' } - return displayValue.length ? displayValue : this.name + + return `${this.name}${suffix}` } } @@ -707,9 +709,11 @@ export class DropdownElementType extends FormElementType { const displayValue = element.label || element.default_value || element.placeholder - if (displayValue && displayValue.length) { - const resolvedName = this.resolveFormula(displayValue, applicationContext) - return resolvedName.length ? resolvedName : this.name + if (displayValue) { + const resolvedName = ensureString( + this.resolveFormula(displayValue, applicationContext) + ).trim() + return resolvedName || this.name } return this.name } @@ -823,8 +827,10 @@ export class IFrameElementType extends ElementType { getDisplayName(element, applicationContext) { if (element.url && element.url.length) { - const resolvedName = this.resolveFormula(element.url, applicationContext) - return resolvedName.length ? resolvedName : this.name + const resolvedName = ensureString( + this.resolveFormula(element.url, applicationContext) + ) + return resolvedName || this.name } return this.name } diff --git a/web-frontend/modules/builder/locales/en.json b/web-frontend/modules/builder/locales/en.json index 40cd3c42e..f5ccd7466 100644 --- a/web-frontend/modules/builder/locales/en.json +++ b/web-frontend/modules/builder/locales/en.json @@ -70,7 +70,7 @@ "heading": "Heading", "headingDescription": "Page heading title", "text": "Text", - "textDescription": "Single line text", + "textDescription": "Multi-line text", "link": "Link", "linkDescription": "A link to page/URL", "image": "Image", @@ -286,7 +286,7 @@ }, "horizontalAlignmentSelector": { "alignment": "Horizontal alignment", - "alignmentLeft": "Link", + "alignmentLeft": "Left", "alignmentCenter": "Center", "alignmentRight": "Right" }, diff --git a/web-frontend/modules/builder/plugin.js b/web-frontend/modules/builder/plugin.js index e820296bc..8f17356cb 100644 --- a/web-frontend/modules/builder/plugin.js +++ b/web-frontend/modules/builder/plugin.js @@ -96,10 +96,6 @@ import { export default (context) => { const { store, app, isDev } = context - if (!app.$featureFlagIsEnabled('builder')) { - return - } - // Allow locale file hot reloading in dev if (isDev && app.i18n) { const { i18n } = app @@ -152,12 +148,10 @@ export default (context) => { new DomainsBuilderSettingsType(context) ) - if (app.$featureFlagIsEnabled('builder-user-source')) { - app.$registry.register( - 'builderSettings', - new UserSourcesBuilderSettingsType(context) - ) - } + app.$registry.register( + 'builderSettings', + new UserSourcesBuilderSettingsType(context) + ) app.$registry.register('errorPage', new PublicSiteErrorPageType(context)) diff --git a/web-frontend/modules/builder/plugins/router.js b/web-frontend/modules/builder/plugins/router.js index 87cb9f3c2..c078a33b1 100644 --- a/web-frontend/modules/builder/plugins/router.js +++ b/web-frontend/modules/builder/plugins/router.js @@ -5,11 +5,6 @@ import { routerOptions as defaultRouterOptions, } from './defaultRouter' -import { - featureFlagIsEnabled, - getFeatureFlags, -} from '@baserow/modules/core/utils/env' - /** * Replace the official Nuxt `createRouter` function. If the request hostname is equal * to the `PUBLIC_WEB_FRONTEND_URL` hostname, the router will contain only routes that @@ -37,11 +32,8 @@ export function createRouter(ssrContext, config) { ).hostname const requestHostname = new URL(`http://${req.headers.host}`).hostname - const featureFlags = getFeatureFlags(runtimeConfig.public) // We allow published routes only if the builder feature flag is on - isWebFrontendHostname = - frontendHostname === requestHostname || - !featureFlagIsEnabled(featureFlags, 'builder') + isWebFrontendHostname = frontendHostname === requestHostname // Send the variable to the frontend using the `__NUXT__` property ssrContext.nuxt.isWebFrontendHostname = isWebFrontendHostname diff --git a/web-frontend/test/unit/builder/elementTypes.spec.js b/web-frontend/test/unit/builder/elementTypes.spec.js index 13c5f75cc..b0d8cc3f1 100644 --- a/web-frontend/test/unit/builder/elementTypes.spec.js +++ b/web-frontend/test/unit/builder/elementTypes.spec.js @@ -197,7 +197,7 @@ describe('elementTypes tests', () => { } expect( elementType.getDisplayName({ data_source_id: 1 }, applicationContext) - ).toBe('Customers elementtype.table') + ).toBe('elementType.table - Customers') // In the event we don't find the data source. expect(