Merge branch 'master' of github.com:Budibase/budibase into bugfixes
This commit is contained in:
commit
ef3e802fad
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
context('Screen Tests', () => {
|
||||||
|
before(() => {
|
||||||
|
cy.visit('localhost:4001/_builder')
|
||||||
|
cy.createApp('Conor Cy App', 'Model App Description')
|
||||||
|
cy.navigateToFrontend()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should successful create a screen', () => {
|
||||||
|
cy.createScreen("test Screen")
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should rename a screen', () => {
|
||||||
|
cy.get(".components-pane").within(() => {
|
||||||
|
cy.contains("Settings").click()
|
||||||
|
cy.get("input[name=_instanceName]").clear().type("About Us").blur()
|
||||||
|
})
|
||||||
|
cy.get('.nav-items-container').within(() => {
|
||||||
|
cy.contains("About Us").should('exist')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -103,3 +103,23 @@ Cypress.Commands.add("addButtonComponent", () => {
|
||||||
|
|
||||||
cy.get("[data-cy=Button]").click()
|
cy.get("[data-cy=Button]").click()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add("navigateToFrontend", () => {
|
||||||
|
cy.get(".close", { timeout: 10000 }).click()
|
||||||
|
cy.contains("frontend").click()
|
||||||
|
cy.get(".close", { timeout: 10000 }).click()
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add("createScreen", (screenName, route) => {
|
||||||
|
cy.get(".newscreen").click()
|
||||||
|
cy.get(".uk-input:first").type(screenName)
|
||||||
|
if (route) {
|
||||||
|
cy.get(".uk-input:last").type(route)
|
||||||
|
}
|
||||||
|
cy.get(".uk-modal-footer").within(() => {
|
||||||
|
cy.contains("Create Screen").click()
|
||||||
|
})
|
||||||
|
cy.get(".nav-items-container").within(() => {
|
||||||
|
cy.contains(screenName).should("exist")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { values } from "lodash/fp"
|
import { values } from "lodash/fp"
|
||||||
|
import { get_capitalised_name } from "../../helpers"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
import * as backendStoreActions from "./backend"
|
import * as backendStoreActions from "./backend"
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import api from "../api"
|
import api from "../api"
|
||||||
|
@ -22,7 +24,6 @@ import {
|
||||||
saveCurrentPreviewItem as _saveCurrentPreviewItem,
|
saveCurrentPreviewItem as _saveCurrentPreviewItem,
|
||||||
saveScreenApi as _saveScreenApi,
|
saveScreenApi as _saveScreenApi,
|
||||||
regenerateCssForCurrentScreen,
|
regenerateCssForCurrentScreen,
|
||||||
renameCurrentScreen,
|
|
||||||
} from "../storeUtils"
|
} from "../storeUtils"
|
||||||
|
|
||||||
export const getStore = () => {
|
export const getStore = () => {
|
||||||
|
@ -68,6 +69,7 @@ export const getStore = () => {
|
||||||
store.getPathToComponent = getPathToComponent(store)
|
store.getPathToComponent = getPathToComponent(store)
|
||||||
store.addTemplatedComponent = addTemplatedComponent(store)
|
store.addTemplatedComponent = addTemplatedComponent(store)
|
||||||
store.setMetadataProp = setMetadataProp(store)
|
store.setMetadataProp = setMetadataProp(store)
|
||||||
|
store.editPageOrScreen = editPageOrScreen(store)
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,14 +154,13 @@ const createScreen = store => (screenName, route, layoutComponentName) => {
|
||||||
const rootComponent = state.components[layoutComponentName]
|
const rootComponent = state.components[layoutComponentName]
|
||||||
|
|
||||||
const newScreen = {
|
const newScreen = {
|
||||||
name: screenName || "",
|
|
||||||
description: "",
|
description: "",
|
||||||
url: "",
|
url: "",
|
||||||
_css: "",
|
_css: "",
|
||||||
props: createProps(rootComponent).props,
|
props: createProps(rootComponent).props,
|
||||||
}
|
}
|
||||||
|
|
||||||
newScreen.route = route
|
newScreen.route = route
|
||||||
|
newScreen.props._instanceName = screenName || ""
|
||||||
state.currentPreviewItem = newScreen
|
state.currentPreviewItem = newScreen
|
||||||
state.currentComponentInfo = newScreen.props
|
state.currentComponentInfo = newScreen.props
|
||||||
state.currentFrontEndType = "screen"
|
state.currentFrontEndType = "screen"
|
||||||
|
@ -172,7 +173,7 @@ const createScreen = store => (screenName, route, layoutComponentName) => {
|
||||||
|
|
||||||
const setCurrentScreen = store => screenName => {
|
const setCurrentScreen = store => screenName => {
|
||||||
store.update(s => {
|
store.update(s => {
|
||||||
const screen = getExactComponent(s.screens, screenName)
|
const screen = getExactComponent(s.screens, screenName, true)
|
||||||
s.currentPreviewItem = screen
|
s.currentPreviewItem = screen
|
||||||
s.currentFrontEndType = "screen"
|
s.currentFrontEndType = "screen"
|
||||||
s.currentView = "detail"
|
s.currentView = "detail"
|
||||||
|
@ -243,6 +244,7 @@ const setCurrentPage = store => pageName => {
|
||||||
const currentPage = state.pages[pageName]
|
const currentPage = state.pages[pageName]
|
||||||
|
|
||||||
state.currentFrontEndType = "page"
|
state.currentFrontEndType = "page"
|
||||||
|
state.currentView = "detail"
|
||||||
state.currentPageName = pageName
|
state.currentPageName = pageName
|
||||||
state.screens = Array.isArray(current_screens)
|
state.screens = Array.isArray(current_screens)
|
||||||
? current_screens
|
? current_screens
|
||||||
|
@ -294,10 +296,15 @@ const addChildComponent = store => (componentToAdd, presetName) => {
|
||||||
|
|
||||||
const presetProps = presetName ? component.presets[presetName] : {}
|
const presetProps = presetName ? component.presets[presetName] : {}
|
||||||
|
|
||||||
|
const instanceId = get(backendUiStore).selectedDatabase._id
|
||||||
|
const instanceName = get_capitalised_name(componentToAdd)
|
||||||
|
|
||||||
const newComponent = createProps(
|
const newComponent = createProps(
|
||||||
component,
|
component,
|
||||||
{
|
{
|
||||||
...presetProps,
|
...presetProps,
|
||||||
|
_instanceId: instanceId,
|
||||||
|
_instanceName: instanceName,
|
||||||
},
|
},
|
||||||
state
|
state
|
||||||
)
|
)
|
||||||
|
@ -346,24 +353,23 @@ const selectComponent = store => component => {
|
||||||
|
|
||||||
const setComponentProp = store => (name, value) => {
|
const setComponentProp = store => (name, value) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const current_component = state.currentComponentInfo
|
let current_component = state.currentComponentInfo
|
||||||
state.currentComponentInfo[name] = value
|
current_component[name] = value
|
||||||
|
|
||||||
_saveCurrentPreviewItem(state)
|
|
||||||
|
|
||||||
state.currentComponentInfo = current_component
|
state.currentComponentInfo = current_component
|
||||||
|
_saveCurrentPreviewItem(state)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const setPageOrScreenProp = store => (name, value) => {
|
const setPageOrScreenProp = store => (name, value) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
if (name === "name" && state.currentFrontEndType === "screen") {
|
if (name === "_instanceName" && state.currentFrontEndType === "screen") {
|
||||||
state = renameCurrentScreen(value, state)
|
state.currentPreviewItem.props[name] = value
|
||||||
} else {
|
} else {
|
||||||
state.currentPreviewItem[name] = value
|
state.currentPreviewItem[name] = value
|
||||||
_saveCurrentPreviewItem(state)
|
|
||||||
}
|
}
|
||||||
|
_saveCurrentPreviewItem(state)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -413,6 +419,18 @@ const setScreenType = store => type => {
|
||||||
|
|
||||||
state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null
|
state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null
|
||||||
state.currentPreviewItem = pageOrScreen
|
state.currentPreviewItem = pageOrScreen
|
||||||
|
state.currentView = "detail"
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const editPageOrScreen = store => (key, value, setOnComponent = false) => {
|
||||||
|
store.update(state => {
|
||||||
|
setOnComponent
|
||||||
|
? (state.currentPreviewItem.props[key] = value)
|
||||||
|
: (state.currentPreviewItem[key] = value)
|
||||||
|
_saveCurrentPreviewItem(state)
|
||||||
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,9 @@ export const saveScreenApi = (screen, s) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const renameCurrentScreen = (newname, state) => {
|
export const renameCurrentScreen = (newname, state) => {
|
||||||
const oldname = state.currentPreviewItem.name
|
const oldname = state.currentPreviewItem.props._instanceName
|
||||||
state.currentPreviewItem.name = newname
|
state.currentPreviewItem.props._instanceName = newname
|
||||||
|
|
||||||
api.patch(
|
api.patch(
|
||||||
`/_builder/api/${state.appId}/pages/${state.currentPageName}/screen`,
|
`/_builder/api/${state.appId}/pages/${state.currentPageName}/screen`,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { setContext, onMount } from "svelte"
|
import { setContext, onMount } from "svelte"
|
||||||
import PropsView from "./PropsView.svelte"
|
import PropsView from "./PropsView.svelte"
|
||||||
|
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import IconButton from "components/common/IconButton.svelte"
|
import IconButton from "components/common/IconButton.svelte"
|
||||||
import {
|
import {
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
let selectedCategory = categories[0]
|
let selectedCategory = categories[0]
|
||||||
|
|
||||||
$: components = $store.components
|
$: components = $store.components
|
||||||
$: componentInstance = $store.currentComponentInfo
|
$: componentInstance = $store.currentView !== "component" ? {...$store.currentPreviewItem, ...$store.currentComponentInfo} : $store.currentComponentInfo
|
||||||
$: componentDefinition = $store.components[componentInstance._component]
|
$: componentDefinition = $store.components[componentInstance._component]
|
||||||
$: componentPropDefinition =
|
$: componentPropDefinition =
|
||||||
flattenedPanel.find(
|
flattenedPanel.find(
|
||||||
|
@ -44,7 +45,19 @@
|
||||||
componentPropDefinition.properties[selectedCategory.value]
|
componentPropDefinition.properties[selectedCategory.value]
|
||||||
|
|
||||||
const onStyleChanged = store.setComponentStyle
|
const onStyleChanged = store.setComponentStyle
|
||||||
const onPropChanged = store.setComponentProp
|
|
||||||
|
function onPropChanged(key, value) {
|
||||||
|
if($store.currentView !== "component") {
|
||||||
|
store.setPageOrScreenProp(key, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
store.setComponentProp(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
$: isComponentOrScreen = $store.currentView === "component" || $store.currentFrontEndType === "screen"
|
||||||
|
$: isNotScreenslot = componentInstance._component !== "##builtin/screenslot"
|
||||||
|
|
||||||
|
$: displayName = isComponentOrScreen && componentInstance._instanceName && isNotScreenslot
|
||||||
|
|
||||||
function walkProps(component, action) {
|
function walkProps(component, action) {
|
||||||
action(component)
|
action(component)
|
||||||
|
@ -79,6 +92,12 @@
|
||||||
{categories}
|
{categories}
|
||||||
{selectedCategory} />
|
{selectedCategory} />
|
||||||
|
|
||||||
|
{#if displayName}
|
||||||
|
<div class="instance-name">
|
||||||
|
<strong>{componentInstance._instanceName}</strong>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="component-props-container">
|
<div class="component-props-container">
|
||||||
{#if selectedCategory.value === 'design'}
|
{#if selectedCategory.value === 'design'}
|
||||||
<DesignView {panelDefinition} {componentInstance} {onStyleChanged} />
|
<DesignView {panelDefinition} {componentInstance} {onStyleChanged} />
|
||||||
|
@ -87,9 +106,10 @@
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
{componentDefinition}
|
{componentDefinition}
|
||||||
{panelDefinition}
|
{panelDefinition}
|
||||||
|
displayNameField={displayName}
|
||||||
onChange={onPropChanged}
|
onChange={onPropChanged}
|
||||||
onScreenPropChange={store.setPageOrScreenProp}
|
screenOrPageInstance={$store.currentView !== "component" && $store.currentPreviewItem} />
|
||||||
screenOrPageInstance={$store.currentView !== 'component' && $store.currentPreviewItem} />
|
|
||||||
{:else if selectedCategory.value === 'events'}
|
{:else if selectedCategory.value === 'events'}
|
||||||
<EventsEditor component={componentInstance} />
|
<EventsEditor component={componentInstance} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -117,8 +137,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.component-props-container {
|
.component-props-container {
|
||||||
margin-top: 20px;
|
margin-top: 10px;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.instance-name {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -22,48 +22,35 @@
|
||||||
trimChars(" "),
|
trimChars(" "),
|
||||||
])
|
])
|
||||||
|
|
||||||
const lastPartOfName = c => {
|
|
||||||
if (!c) return ""
|
|
||||||
const name = c.name ? c.name : c._component ? c._component : c
|
|
||||||
return last(name.split("/"))
|
|
||||||
}
|
|
||||||
|
|
||||||
const isComponentSelected = (current, comp) => current === comp
|
|
||||||
|
|
||||||
$: _screens = pipe(screens, [
|
|
||||||
map(c => ({ component: c, title: lastPartOfName(c) })),
|
|
||||||
sortBy("title"),
|
|
||||||
])
|
|
||||||
|
|
||||||
const changeScreen = screen => {
|
const changeScreen = screen => {
|
||||||
store.setCurrentScreen(screen.title)
|
store.setCurrentScreen(screen.props._instanceName)
|
||||||
$goto(`./:page/${screen.title}`)
|
$goto(`./:page/${screen.title}`)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
{#each _screens as screen}
|
{#each screens as screen}
|
||||||
<div
|
<div
|
||||||
class="budibase__nav-item component"
|
class="budibase__nav-item component"
|
||||||
class:selected={$store.currentComponentInfo._id === screen.component.props._id}
|
class:selected={$store.currentComponentInfo._id === screen.props._id}
|
||||||
on:click|stopPropagation={() => changeScreen(screen)}>
|
on:click|stopPropagation={() => changeScreen(screen)}>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
class:rotate={$store.currentPreviewItem.name !== screen.title}>
|
class:rotate={$store.currentPreviewItem.name !== screen.props._instanceName}>
|
||||||
{#if screen.component.props._children.length}
|
{#if screen.props._children.length}
|
||||||
<ArrowDownIcon />
|
<ArrowDownIcon />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<i class="ri-artboard-2-fill icon" />
|
<i class="ri-artboard-2-fill icon" />
|
||||||
|
|
||||||
<span class="title">{screen.title}</span>
|
<span class="title">{screen.props._instanceName}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if $store.currentPreviewItem.name === screen.title && screen.component.props._children}
|
{#if $store.currentPreviewItem.props._instanceName && $store.currentPreviewItem.props._instanceName === screen.props._instanceName && screen.props._children}
|
||||||
<ComponentsHierarchyChildren
|
<ComponentsHierarchyChildren
|
||||||
components={screen.component.props._children}
|
components={screen.props._children}
|
||||||
currentComponent={$store.currentComponentInfo} />
|
currentComponent={$store.currentComponentInfo} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
const get_name = s => (!s ? "" : last(s.split("/")))
|
const get_name = s => (!s ? "" : last(s.split("/")))
|
||||||
|
|
||||||
const get_capitalised_name = name => pipe(name, [get_name, capitalise])
|
const get_capitalised_name = name => pipe(name, [get_name, capitalise])
|
||||||
|
const isScreenslot = name => name === "##builtin/screenslot"
|
||||||
|
|
||||||
const selectComponent = component => {
|
const selectComponent = component => {
|
||||||
// Set current component
|
// Set current component
|
||||||
|
@ -42,7 +43,7 @@
|
||||||
style="padding-left: {level * 20 + 40}px">
|
style="padding-left: {level * 20 + 40}px">
|
||||||
<div class="nav-item">
|
<div class="nav-item">
|
||||||
<i class="icon ri-arrow-right-circle-fill" />
|
<i class="icon ri-arrow-right-circle-fill" />
|
||||||
{get_capitalised_name(component._component)}
|
{isScreenslot(component._component) ? "Screenslot" : component._instanceName}
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<ComponentDropdownMenu {component} />
|
<ComponentDropdownMenu {component} />
|
||||||
|
|
|
@ -1,34 +1,27 @@
|
||||||
<script>
|
<script>
|
||||||
import PropertyControl from "./PropertyControl.svelte"
|
import PropertyControl from "./PropertyControl.svelte"
|
||||||
import InputGroup from "../common/Inputs/InputGroup.svelte"
|
import InputGroup from "../common/Inputs/InputGroup.svelte"
|
||||||
|
import Input from "../common/Input.svelte"
|
||||||
import Colorpicker from "../common/Colorpicker.svelte"
|
import Colorpicker from "../common/Colorpicker.svelte"
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { excludeProps } from "./propertyCategories.js"
|
import { excludeProps } from "./propertyCategories.js"
|
||||||
import Input from "../common/Input.svelte"
|
|
||||||
|
|
||||||
export let panelDefinition = []
|
export let panelDefinition = []
|
||||||
export let componentDefinition = {}
|
export let componentDefinition = {}
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let onChange = () => {}
|
export let onChange = () => {}
|
||||||
export let onScreenPropChange = () => {}
|
export let displayNameField = false
|
||||||
export let screenOrPageInstance
|
export let screenOrPageInstance
|
||||||
|
|
||||||
const propExistsOnComponentDef = prop => prop in componentDefinition.props
|
let pageScreenProps = ["title","favicon", "description", "route"]
|
||||||
|
|
||||||
|
const propExistsOnComponentDef = prop => pageScreenProps.includes(prop) || prop in componentDefinition.props
|
||||||
|
|
||||||
function handleChange(key, data) {
|
function handleChange(key, data) {
|
||||||
data.target ? onChange(key, data.target.value) : onChange(key, data)
|
data.target ? onChange(key, data.target.value) : onChange(key, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleScreenPropChange(name, value) {
|
|
||||||
onScreenPropChange(name, value)
|
|
||||||
if (!isPage && name === "name") {
|
|
||||||
// screen name is changed... change URL
|
|
||||||
$goto(`./:page/${value}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const screenDefinition = [
|
const screenDefinition = [
|
||||||
{ key: "name", label: "Name", control: Input },
|
|
||||||
{ key: "description", label: "Description", control: Input },
|
{ key: "description", label: "Description", control: Input },
|
||||||
{ key: "route", label: "Route", control: Input },
|
{ key: "route", label: "Route", control: Input },
|
||||||
]
|
]
|
||||||
|
@ -49,12 +42,16 @@
|
||||||
label={def.label}
|
label={def.label}
|
||||||
key={def.key}
|
key={def.key}
|
||||||
value={screenOrPageInstance[def.key]}
|
value={screenOrPageInstance[def.key]}
|
||||||
onChange={handleScreenPropChange}
|
{onChange}
|
||||||
props={{ ...excludeProps(def, ['control', 'label']) }} />
|
props={{ ...excludeProps(def, ['control', 'label']) }} />
|
||||||
{/each}
|
{/each}
|
||||||
<hr />
|
<hr />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if displayNameField}
|
||||||
|
<PropertyControl control={Input} label="Name" key="_instanceName" value={componentInstance._instanceName} {onChange} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if panelDefinition && panelDefinition.length > 0}
|
{#if panelDefinition && panelDefinition.length > 0}
|
||||||
{#each panelDefinition as definition}
|
{#each panelDefinition as definition}
|
||||||
{#if propExistsOnComponentDef(definition.key)}
|
{#if propExistsOnComponentDef(definition.key)}
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const rename = (pages, screens, oldname, newname) => {
|
||||||
screens = cloneDeep(screens)
|
screens = cloneDeep(screens)
|
||||||
const changedScreens = []
|
const changedScreens = []
|
||||||
|
|
||||||
const existingWithNewName = getExactComponent(screens, newname)
|
const existingWithNewName = getExactComponent(screens, newname, true)
|
||||||
if (existingWithNewName)
|
if (existingWithNewName)
|
||||||
return {
|
return {
|
||||||
components: screens,
|
components: screens,
|
||||||
|
@ -38,19 +38,15 @@ export const rename = (pages, screens, oldname, newname) => {
|
||||||
for (let screen of screens) {
|
for (let screen of screens) {
|
||||||
let hasEdited = false
|
let hasEdited = false
|
||||||
|
|
||||||
if (screen.name === oldname) {
|
if (screen.props.instanceName === oldname) {
|
||||||
screen.name = newname
|
screen.props.instanceName = newname
|
||||||
hasEdited = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen.props._component === oldname) {
|
|
||||||
screen.props._component = newname
|
|
||||||
hasEdited = true
|
hasEdited = true
|
||||||
}
|
}
|
||||||
|
|
||||||
hasEdited = traverseProps(screen.props) || hasEdited
|
hasEdited = traverseProps(screen.props) || hasEdited
|
||||||
|
|
||||||
if (hasEdited && screen.name !== newname) changedScreens.push(screen.name)
|
if (hasEdited && screen.props.instanceName !== newname)
|
||||||
|
changedScreens.push(screen.props.instanceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let pageName in pages) {
|
for (let pageName in pages) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { find, isUndefined, filter, some, includes } from "lodash/fp"
|
import { isUndefined, filter, some, includes } from "lodash/fp"
|
||||||
import { pipe } from "components/common/core"
|
import { pipe } from "components/common/core"
|
||||||
|
|
||||||
const normalString = s => (s || "").trim().toLowerCase()
|
const normalString = s => (s || "").trim().toLowerCase()
|
||||||
|
@ -16,7 +16,7 @@ export const searchAllComponents = (components, phrase) => {
|
||||||
pipe(vals, [some(v => includes(normalString(phrase))(normalString(v)))])
|
pipe(vals, [some(v => includes(normalString(phrase))(normalString(v)))])
|
||||||
|
|
||||||
const componentMatches = c => {
|
const componentMatches = c => {
|
||||||
if (hasPhrase(c.name, ...(c.tags || []))) return true
|
if (hasPhrase(c._instanceName, ...(c.tags || []))) return true
|
||||||
|
|
||||||
if (isRootComponent(c)) return false
|
if (isRootComponent(c)) return false
|
||||||
|
|
||||||
|
@ -28,10 +28,10 @@ export const searchAllComponents = (components, phrase) => {
|
||||||
return filter(componentMatches)(components)
|
return filter(componentMatches)(components)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getExactComponent = (components, name) => {
|
export const getExactComponent = (components, name, isScreen = false) => {
|
||||||
const stringEquals = (s1, s2) => normalString(s1) === normalString(s2)
|
return components.find(c =>
|
||||||
|
isScreen ? c.props._instanceName === name : c._instanceName === name
|
||||||
return pipe(components, [find(c => stringEquals(c.name, name))])
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAncestorProps = (components, name, found = []) => {
|
export const getAncestorProps = (components, name, found = []) => {
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { last } from "lodash/fp"
|
||||||
|
import { pipe } from "components/common/core"
|
||||||
|
|
||||||
export const buildStyle = styles => {
|
export const buildStyle = styles => {
|
||||||
let str = ""
|
let str = ""
|
||||||
for (let s in styles) {
|
for (let s in styles) {
|
||||||
|
@ -12,3 +15,9 @@ export const buildStyle = styles => {
|
||||||
export const convertCamel = str => {
|
export const convertCamel = str => {
|
||||||
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)
|
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1)
|
||||||
|
|
||||||
|
export const get_name = s => (!s ? "" : last(s.split("/")))
|
||||||
|
|
||||||
|
export const get_capitalised_name = name => pipe(name, [get_name, capitalise])
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
import { getExactComponent } from "../src/components/userInterface/pagesParsing/searchComponents"
|
|
||||||
import { rename } from "../src/components/userInterface/pagesParsing/renameScreen"
|
|
||||||
import { componentsAndScreens } from "./testData"
|
|
||||||
|
|
||||||
describe("rename component", () => {
|
|
||||||
it("should change the name of the component, duh", () => {
|
|
||||||
const { screens } = componentsAndScreens()
|
|
||||||
|
|
||||||
const result = rename({}, screens, "PrimaryButton", "MainButton")
|
|
||||||
|
|
||||||
const newComponent = getExactComponent(result.screens, "MainButton")
|
|
||||||
const oldComponent = getExactComponent(result.screens, "Primary")
|
|
||||||
expect(oldComponent).toBeUndefined()
|
|
||||||
expect(newComponent).toBeDefined()
|
|
||||||
expect(newComponent.name).toBe("MainButton")
|
|
||||||
})
|
|
||||||
|
|
||||||
/* this may be usefull if we have user defined components
|
|
||||||
it("should change name of nested _components", () => {
|
|
||||||
const {screens} = componentsAndScreens();
|
|
||||||
const result = rename({}, screens, "PrimaryButton", "MainButton");
|
|
||||||
|
|
||||||
const buttonGroup = getExactComponent(result.screens, "ButtonGroup");
|
|
||||||
expect(buttonGroup.props.header[0]._component).toBe("MainButton");
|
|
||||||
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
it("should change name of page appBody", () => {
|
|
||||||
const { screens } = componentsAndScreens()
|
|
||||||
const pages = {
|
|
||||||
main: {
|
|
||||||
appBody: "PrimaryButton",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = rename(pages, screens, "PrimaryButton", "MainButton")
|
|
||||||
expect(result.pages.main.appBody).toBe("MainButton")
|
|
||||||
})
|
|
||||||
|
|
||||||
/* this may be usefull if we have user defined components
|
|
||||||
it("should return a list of changed components", () => {
|
|
||||||
const {screens} = componentsAndScreens();
|
|
||||||
const result = rename({}, screens, "PrimaryButton", "MainButton");
|
|
||||||
|
|
||||||
expect(result.changedScreens).toEqual(["ButtonGroup"]);
|
|
||||||
|
|
||||||
const result2 = rename({}, screens, "common/SmallTextbox", "common/TinyTextBox");
|
|
||||||
expect(result2.changedScreens).toEqual(["Field"]);
|
|
||||||
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
})
|
|
|
@ -5,70 +5,33 @@ import {
|
||||||
} from "../src/components/userInterface/pagesParsing/searchComponents"
|
} from "../src/components/userInterface/pagesParsing/searchComponents"
|
||||||
import { componentsAndScreens } from "./testData"
|
import { componentsAndScreens } from "./testData"
|
||||||
|
|
||||||
describe("searchAllComponents", () => {
|
|
||||||
it("should match component by name", () => {
|
|
||||||
const results = searchAllComponents(
|
|
||||||
componentsAndScreens().components,
|
|
||||||
"Textbox"
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(results.length).toBe(1)
|
|
||||||
expect(results[0].name).toBe("budibase-components/TextBox")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should match component by tag", () => {
|
|
||||||
const results = searchAllComponents(
|
|
||||||
componentsAndScreens().components,
|
|
||||||
"record"
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(results.length).toBe(1)
|
|
||||||
expect(results[0].name).toBe("budibase-components/RecordView")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("getExactComponent", () => {
|
describe("getExactComponent", () => {
|
||||||
it("should get component by name", () => {
|
it("should get component by name", () => {
|
||||||
const { components, screens } = componentsAndScreens()
|
const { components } = componentsAndScreens()
|
||||||
const result = getExactComponent(
|
const result = getExactComponent(
|
||||||
[...components, ...screens],
|
components,
|
||||||
"common/SmallTextbox"
|
"TextBox"
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result).toBeDefined()
|
expect(result).toBeDefined()
|
||||||
expect(result.name).toBe("common/SmallTextbox")
|
expect(result._instanceName).toBe("TextBox")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should return nothing when no result (should not fail)", () => {
|
test("Should not find as isScreen is not specified", () => {
|
||||||
const { components, screens } = componentsAndScreens()
|
const { screens } = componentsAndScreens()
|
||||||
const result = getExactComponent([...components, ...screens], "bla/bla/bla")
|
const result = getExactComponent(screens, "SmallTextbox")
|
||||||
|
|
||||||
expect(result).not.toBeDefined()
|
expect(result).not.toBeDefined()
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
describe("getAncestorProps", () => {
|
test("Should find as isScreen is specified", () => {
|
||||||
it("should return props of root component", () => {
|
const { screens } = componentsAndScreens()
|
||||||
const result = getAncestorProps(
|
const result = getExactComponent(screens, "SmallTextbox", true)
|
||||||
componentsAndScreens().components,
|
|
||||||
"budibase-components/TextBox"
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(result).toEqual([componentsAndScreens().components[0].props])
|
expect(result).toBeDefined()
|
||||||
})
|
expect(result.props._instanceName).toBe("SmallTextbox")
|
||||||
|
|
||||||
it("should return props of inherited and current component, in order", () => {
|
|
||||||
const { components, screens } = componentsAndScreens()
|
|
||||||
const allComponentsAndScreens = [...components, ...screens]
|
|
||||||
|
|
||||||
const result = getAncestorProps(
|
|
||||||
allComponentsAndScreens,
|
|
||||||
"common/PasswordBox"
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(result).toEqual([
|
|
||||||
allComponentsAndScreens[0].props,
|
|
||||||
{ ...allComponentsAndScreens[5].props },
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export const componentsAndScreens = () => ({
|
export const componentsAndScreens = () => ({
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
name: "budibase-components/TextBox",
|
_instanceName: "TextBox",
|
||||||
tags: ["Text", "input"],
|
tags: ["Text", "input"],
|
||||||
children: false,
|
children: false,
|
||||||
props: {
|
props: {
|
||||||
|
@ -12,7 +12,7 @@ export const componentsAndScreens = () => ({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "budibase-components/Button",
|
_instanceName: "Button",
|
||||||
tags: ["input"],
|
tags: ["input"],
|
||||||
children: true,
|
children: true,
|
||||||
props: {
|
props: {
|
||||||
|
@ -22,14 +22,14 @@ export const componentsAndScreens = () => ({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "budibase-components/div",
|
_instanceName: "div",
|
||||||
tags: ["input"],
|
tags: ["input"],
|
||||||
props: {
|
props: {
|
||||||
width: "number",
|
width: "number",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "budibase-components/RecordView",
|
_instanceName: "Record View",
|
||||||
tags: ["record"],
|
tags: ["record"],
|
||||||
props: {
|
props: {
|
||||||
data: "state",
|
data: "state",
|
||||||
|
@ -38,9 +38,9 @@ export const componentsAndScreens = () => ({
|
||||||
],
|
],
|
||||||
screens: [
|
screens: [
|
||||||
{
|
{
|
||||||
name: "common/SmallTextbox",
|
|
||||||
props: {
|
props: {
|
||||||
_component: "budibase-components/TextBox",
|
_component: "budibase-components/TextBox",
|
||||||
|
_instanceName: "SmallTextbox",
|
||||||
size: "small",
|
size: "small",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -50,36 +50,40 @@ export const componentsAndScreens = () => ({
|
||||||
tags: ["mask"],
|
tags: ["mask"],
|
||||||
props: {
|
props: {
|
||||||
_component: "budibase-components/TextBox",
|
_component: "budibase-components/TextBox",
|
||||||
|
_instanceName: "PasswordBox",
|
||||||
isPassword: true,
|
isPassword: true,
|
||||||
size: "small",
|
size: "small",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "PrimaryButton",
|
|
||||||
props: {
|
props: {
|
||||||
_component: "budibase-components/Button",
|
_component: "budibase-components/Button",
|
||||||
|
_instanceName: "PrimaryButton",
|
||||||
css: "btn-primary",
|
css: "btn-primary",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "Screen 1",
|
|
||||||
route: "",
|
route: "",
|
||||||
props: {
|
props: {
|
||||||
_component: "budibase-components/div",
|
_component: "budibase-components/div",
|
||||||
width: 100,
|
width: 100,
|
||||||
|
_instanceName: "Screen 1",
|
||||||
_children: [
|
_children: [
|
||||||
{
|
{
|
||||||
_component: "budibase-components/Button",
|
_component: "budibase-components/Button",
|
||||||
contentText: "Button 1",
|
contentText: "Button 1",
|
||||||
|
_instanceName: "Button 1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "budibase-components/Button",
|
_component: "budibase-components/Button",
|
||||||
contentText: "Button 2",
|
contentText: "Button 2",
|
||||||
|
_instanceName: "Button 2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "budibase-components/TextBox",
|
_component: "budibase-components/TextBox",
|
||||||
|
_instanceName: "TextBox",
|
||||||
isPassword: true,
|
isPassword: true,
|
||||||
size: "small",
|
size: "small",
|
||||||
},
|
},
|
||||||
|
@ -88,9 +92,9 @@ export const componentsAndScreens = () => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "Field",
|
|
||||||
props: {
|
props: {
|
||||||
_component: "budibase-components/div",
|
_component: "budibase-components/div",
|
||||||
|
_instanceName: "Field",
|
||||||
_children: [
|
_children: [
|
||||||
{
|
{
|
||||||
_component: "common/SmallTextbox",
|
_component: "common/SmallTextbox",
|
||||||
|
|
|
@ -41,7 +41,8 @@ const screenPath = (appPath, pageName, name) =>
|
||||||
|
|
||||||
module.exports.saveScreen = async (config, appname, pagename, screen) => {
|
module.exports.saveScreen = async (config, appname, pagename, screen) => {
|
||||||
const appPath = appPackageFolder(config, appname)
|
const appPath = appPackageFolder(config, appname)
|
||||||
const compPath = screenPath(appPath, pagename, screen.name)
|
const compPath = screenPath(appPath, pagename, screen.props._id)
|
||||||
|
|
||||||
await ensureDir(dirname(compPath))
|
await ensureDir(dirname(compPath))
|
||||||
if (screen._css) {
|
if (screen._css) {
|
||||||
delete screen._css
|
delete screen._css
|
||||||
|
|
Loading…
Reference in New Issue