mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-10 15:47:32 +00:00
Resolve "Name elements in the element modal"
This commit is contained in:
parent
55672c2117
commit
a8695a5883
5 changed files with 383 additions and 19 deletions
web-frontend
locales
modules/builder
test/unit/builder
|
@ -5,7 +5,9 @@
|
|||
"wrong": "Something went wrong",
|
||||
"none": "None",
|
||||
"free": "Free",
|
||||
"comingSoon": "Coming soon..."
|
||||
"comingSoon": "Coming soon...",
|
||||
"table": "Table",
|
||||
"link": "Link"
|
||||
},
|
||||
"action": {
|
||||
"upload": "Upload",
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
<a class="select__item-link" @click="$emit('click')">
|
||||
<span class="select__item-name">
|
||||
<i :class="`${elementType.iconClass} select__item-icon`"></i>
|
||||
<span class="select__item-name-text">{{ elementType.name }}</span>
|
||||
<span class="select__item-name-text">{{
|
||||
elementType.getDisplayName(element, applicationContext)
|
||||
}}</span>
|
||||
</span>
|
||||
</a>
|
||||
</template>
|
||||
|
@ -10,6 +12,7 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'ElementsListItem',
|
||||
inject: ['builder', 'page', 'mode'],
|
||||
props: {
|
||||
element: {
|
||||
type: Object,
|
||||
|
@ -20,6 +23,14 @@ export default {
|
|||
elementType() {
|
||||
return this.$registry.get('element', this.element.type)
|
||||
},
|
||||
applicationContext() {
|
||||
return {
|
||||
builder: this.builder,
|
||||
page: this.page,
|
||||
mode: this.mode,
|
||||
element: this.element,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -387,7 +387,7 @@ export class FormDataProviderType extends DataProviderType {
|
|||
parseInt(elementId)
|
||||
)
|
||||
const elementType = this.app.$registry.get('element', element.type)
|
||||
const name = elementType.getFormDataName(element, applicationContext)
|
||||
const name = elementType.getDisplayName(element, applicationContext)
|
||||
const order = this.app.store.getters['element/getElementPosition'](
|
||||
page,
|
||||
element
|
||||
|
|
|
@ -86,6 +86,17 @@ export class ElementType extends Registerable {
|
|||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a display name for this element, so it can be distinguished from
|
||||
* other elements of the same type.
|
||||
* @param {object} element - The element we want to get a display name for.
|
||||
* @param {object} applicationContext - The context of the current application
|
||||
* @returns {string} this element's display name.
|
||||
*/
|
||||
getDisplayName(element, applicationContext) {
|
||||
return this.name
|
||||
}
|
||||
|
||||
getEvents() {
|
||||
return this.events.map((EventType) => new EventType(this.app))
|
||||
}
|
||||
|
@ -277,25 +288,21 @@ export class FormElementType extends ElementType {
|
|||
}
|
||||
|
||||
/**
|
||||
* This name is used by the data explorer to show the form element.
|
||||
*
|
||||
* @param element - The form element instance
|
||||
* @param applicationContext - The context of the current application
|
||||
* @returns {string} - The name of the form element
|
||||
* Returns a display name for this element, so it can be distinguished from
|
||||
* other elements of the same type.
|
||||
* @param {object} element - The element we want to get a display name for.
|
||||
* @param {object} applicationContext
|
||||
* @returns {string} this element's display name.
|
||||
*/
|
||||
getFormDataName(element, applicationContext) {
|
||||
getDisplayName(element, applicationContext) {
|
||||
if (element.label) {
|
||||
return this.resolveFormula(element.label, applicationContext)
|
||||
const resolvedName = this.resolveFormula(
|
||||
element.label,
|
||||
applicationContext
|
||||
)
|
||||
return resolvedName.length ? resolvedName : this.name
|
||||
}
|
||||
|
||||
return this.generateFromDataName(element, applicationContext)
|
||||
}
|
||||
|
||||
generateFromDataName(element, applicationContext) {
|
||||
const elementPosition = this.app.store.getters[
|
||||
'element/getElementPosition'
|
||||
](applicationContext.page, element, true)
|
||||
return `${this.name} ${elementPosition}`
|
||||
return this.name
|
||||
}
|
||||
|
||||
afterCreate(element, page) {
|
||||
|
@ -348,6 +355,17 @@ export class InputTextElementType extends FormElementType {
|
|||
return 'string'
|
||||
}
|
||||
|
||||
getDisplayName(element, applicationContext) {
|
||||
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
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
|
||||
getInitialFormDataValue(element, applicationContext) {
|
||||
return this.resolveFormula(element.default_value, {
|
||||
element,
|
||||
|
@ -380,6 +398,17 @@ export class HeadingElementType extends ElementType {
|
|||
get generalFormComponent() {
|
||||
return HeadingElementForm
|
||||
}
|
||||
|
||||
getDisplayName(element, applicationContext) {
|
||||
if (element.value && element.value.length) {
|
||||
const resolvedName = this.resolveFormula(
|
||||
element.value,
|
||||
applicationContext
|
||||
)
|
||||
return resolvedName.length ? resolvedName : this.name
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
}
|
||||
|
||||
export class TextElementType extends ElementType {
|
||||
|
@ -406,6 +435,17 @@ export class TextElementType extends ElementType {
|
|||
get generalFormComponent() {
|
||||
return TextElementForm
|
||||
}
|
||||
|
||||
getDisplayName(element, applicationContext) {
|
||||
if (element.value && element.value.length) {
|
||||
const resolvedName = this.resolveFormula(
|
||||
element.value,
|
||||
applicationContext
|
||||
)
|
||||
return resolvedName.length ? resolvedName : this.name
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
}
|
||||
|
||||
export class LinkElementType extends ElementType {
|
||||
|
@ -436,6 +476,37 @@ export class LinkElementType extends ElementType {
|
|||
isInError({ element, builder }) {
|
||||
return pathParametersInError(element, builder)
|
||||
}
|
||||
|
||||
getDisplayName(element, applicationContext) {
|
||||
let displayValue = ''
|
||||
let destination = ''
|
||||
if (element.navigation_type === 'page') {
|
||||
const builder = applicationContext.builder
|
||||
const destinationPage = builder.pages.find(
|
||||
({ id }) => id === element.navigate_to_page_id
|
||||
)
|
||||
if (destinationPage) {
|
||||
destination = `${destinationPage.name}`
|
||||
}
|
||||
} else if (element.navigation_type === 'custom') {
|
||||
destination = this.resolveFormula(
|
||||
element.navigate_to_url,
|
||||
applicationContext
|
||||
)
|
||||
}
|
||||
|
||||
if (destination) {
|
||||
destination = ` -> ${destination}`
|
||||
}
|
||||
|
||||
if (element.value) {
|
||||
displayValue = this.resolveFormula(element.value, applicationContext)
|
||||
}
|
||||
|
||||
return displayValue
|
||||
? `${displayValue}${destination}`
|
||||
: `${this.name}${destination}`
|
||||
}
|
||||
}
|
||||
|
||||
export class ImageElementType extends ElementType {
|
||||
|
@ -462,6 +533,17 @@ export class ImageElementType extends ElementType {
|
|||
get generalFormComponent() {
|
||||
return ImageElementForm
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
}
|
||||
|
||||
export class ButtonElementType extends ElementType {
|
||||
|
@ -492,6 +574,17 @@ export class ButtonElementType extends ElementType {
|
|||
get events() {
|
||||
return [ClickEvent]
|
||||
}
|
||||
|
||||
getDisplayName(element, applicationContext) {
|
||||
if (element.value && element.value.length) {
|
||||
const resolvedName = this.resolveFormula(
|
||||
element.value,
|
||||
applicationContext
|
||||
)
|
||||
return resolvedName.length ? resolvedName : this.name
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
}
|
||||
|
||||
export class TableElementType extends ElementType {
|
||||
|
@ -559,6 +652,19 @@ export class TableElementType extends ElementType {
|
|||
})
|
||||
return collectionFieldsInError.includes(true)
|
||||
}
|
||||
|
||||
getDisplayName(element, { page }) {
|
||||
let displayValue = ''
|
||||
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()}`
|
||||
: ''
|
||||
}
|
||||
return displayValue.length ? displayValue : this.name
|
||||
}
|
||||
}
|
||||
|
||||
export class DropdownElementType extends FormElementType {
|
||||
|
@ -596,6 +702,17 @@ export class DropdownElementType extends FormElementType {
|
|||
...applicationContext,
|
||||
})
|
||||
}
|
||||
|
||||
getDisplayName(element, applicationContext) {
|
||||
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
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
}
|
||||
|
||||
export class FormContainerElementType extends ContainerElementType {
|
||||
|
@ -703,4 +820,12 @@ export class IFrameElementType extends ElementType {
|
|||
get generalFormComponent() {
|
||||
return IFrameElementForm
|
||||
}
|
||||
|
||||
getDisplayName(element, applicationContext) {
|
||||
if (element.url && element.url.length) {
|
||||
const resolvedName = this.resolveFormula(element.url, applicationContext)
|
||||
return resolvedName.length ? resolvedName : this.name
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
}
|
||||
|
|
226
web-frontend/test/unit/builder/elementTypes.spec.js
Normal file
226
web-frontend/test/unit/builder/elementTypes.spec.js
Normal file
|
@ -0,0 +1,226 @@
|
|||
import { ElementType } from '@baserow/modules/builder/elementTypes'
|
||||
import { TestApp } from '@baserow/test/helpers/testApp'
|
||||
|
||||
describe('elementTypes tests', () => {
|
||||
const testApp = new TestApp()
|
||||
|
||||
const contextBlankParam = { page: { parameters: { id: '' } } }
|
||||
|
||||
describe('elementType getDisplayName permutation tests', () => {
|
||||
test('ElementType returns the name by default', () => {
|
||||
const elementType = new ElementType()
|
||||
expect(elementType.getDisplayName({}, {})).toBe(null)
|
||||
})
|
||||
test('ColumnElementType returns the name by default', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'column')
|
||||
expect(elementType.getDisplayName({}, {})).toBe('elementType.column')
|
||||
})
|
||||
test('InputTextElementType label and default_value variations', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'input_text')
|
||||
expect(elementType.getDisplayName({ label: "'First name'" }, {})).toBe(
|
||||
'First name'
|
||||
)
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ default_value: "'Enter a first name'" },
|
||||
{}
|
||||
)
|
||||
).toBe('Enter a first name')
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ placeholder: "'Choose a first name...'" },
|
||||
{}
|
||||
)
|
||||
).toBe('Choose a first name...')
|
||||
// If a formula resolves to a blank string, fallback to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ label: "get('page_parameter.id')" },
|
||||
contextBlankParam
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('DropdownElementType label, default_value & placeholder variations', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'dropdown')
|
||||
expect(elementType.getDisplayName({ label: "'Animals'" }, {})).toBe(
|
||||
'Animals'
|
||||
)
|
||||
expect(elementType.getDisplayName({ default_value: "'Horse'" }, {})).toBe(
|
||||
'Horse'
|
||||
)
|
||||
expect(
|
||||
elementType.getDisplayName({ default_value: "'Choose an animal'" }, {})
|
||||
).toBe('Choose an animal')
|
||||
// If a formula resolves to a blank string, fallback to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ label: "get('page_parameter.id')" },
|
||||
contextBlankParam
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('CheckboxElementType with and without a label to use', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'checkbox')
|
||||
expect(elementType.getDisplayName({ label: "'Active'" }, {})).toBe(
|
||||
'Active'
|
||||
)
|
||||
// If a formula resolves to a blank string, fallback to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ label: "get('page_parameter.id')" },
|
||||
contextBlankParam
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('HeadingElementType with and without a value to use', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'heading')
|
||||
expect(elementType.getDisplayName({ value: "'A heading'" }, {})).toBe(
|
||||
'A heading'
|
||||
)
|
||||
// If a formula resolves to a blank string, fallback to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ value: "get('page_parameter.id')" },
|
||||
contextBlankParam
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('TextElementType with and without a value to use', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'text')
|
||||
expect(elementType.getDisplayName({ value: "'Some text'" }, {})).toBe(
|
||||
'Some text'
|
||||
)
|
||||
// If a formula resolves to a blank string, fallback to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ value: "get('page_parameter.id')" },
|
||||
contextBlankParam
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('LinkElementType page and custom URL variations', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'link')
|
||||
const applicationContext = {
|
||||
builder: {
|
||||
pages: [{ id: 1, name: 'Contact Us' }],
|
||||
},
|
||||
}
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{
|
||||
navigate_to_page_id: 1,
|
||||
navigation_type: 'page',
|
||||
},
|
||||
applicationContext
|
||||
)
|
||||
).toBe('elementType.link -> Contact Us')
|
||||
|
||||
// If we were not able to find the page, we fall back to trying for a value.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{
|
||||
value: "'Click me'",
|
||||
navigate_to_page_id: 2,
|
||||
navigation_type: 'page',
|
||||
},
|
||||
applicationContext
|
||||
)
|
||||
).toBe('Click me')
|
||||
|
||||
// If we were not able to find the page, and there's no value, we fall back to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{
|
||||
navigate_to_page_id: 2,
|
||||
navigation_type: 'page',
|
||||
},
|
||||
applicationContext
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{
|
||||
navigation_type: 'custom',
|
||||
navigate_to_url: "'https://baserow.io'",
|
||||
value: "'Link name'",
|
||||
},
|
||||
applicationContext
|
||||
)
|
||||
).toBe('Link name -> https://baserow.io')
|
||||
})
|
||||
test('ImageElementType with and without alt text to use', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'image')
|
||||
expect(
|
||||
elementType.getDisplayName({ alt_text: "'Baserow logo'" }, {})
|
||||
).toBe('Baserow logo')
|
||||
// If a formula resolves to a blank string, fallback to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ alt_text: "get('page_parameter.id')" },
|
||||
contextBlankParam
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('ButtonElementType with and without value to use', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'button')
|
||||
expect(elementType.getDisplayName({ value: "'Click me'" }, {})).toBe(
|
||||
'Click me'
|
||||
)
|
||||
// If a formula resolves to a blank string, fallback to the name.
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ value: "get('page_parameter.id')" },
|
||||
contextBlankParam
|
||||
)
|
||||
).toBe(elementType.name)
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('TableElementType with and without data_source_id to use', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'table')
|
||||
const page = {
|
||||
id: 1,
|
||||
name: 'Contact Us',
|
||||
dataSources: [
|
||||
{ id: 1, type: 'local_baserow_list_rows', name: 'Customers' },
|
||||
],
|
||||
}
|
||||
const applicationContext = {
|
||||
page,
|
||||
builder: { pages: [page] },
|
||||
}
|
||||
expect(
|
||||
elementType.getDisplayName({ data_source_id: 1 }, applicationContext)
|
||||
).toBe('Customers elementtype.table')
|
||||
|
||||
// In the event we don't find the data source.
|
||||
expect(
|
||||
elementType.getDisplayName({ data_source_id: 2 }, applicationContext)
|
||||
).toBe(elementType.name)
|
||||
|
||||
expect(elementType.getDisplayName({}, applicationContext)).toBe(
|
||||
elementType.name
|
||||
)
|
||||
})
|
||||
test('FormContainerElementType returns the name by default', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'form_container')
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
test('IFrameElementType with and without a url to use', () => {
|
||||
const elementType = testApp.getRegistry().get('element', 'iframe')
|
||||
expect(
|
||||
elementType.getDisplayName(
|
||||
{ url: "'https://www.youtube.com/watch?v=dQw4w9WgXcQ'" },
|
||||
{}
|
||||
)
|
||||
).toBe('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
|
||||
expect(elementType.getDisplayName({}, {})).toBe(elementType.name)
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Add table
Reference in a new issue