Screen templates working

This commit is contained in:
Michael Shanks 2020-10-07 22:30:00 +01:00
parent 6625cb691a
commit b7eb1a35e8
11 changed files with 174 additions and 38 deletions

View File

@ -8,8 +8,9 @@ export default function(component, state) {
const findMatches = props => { const findMatches = props => {
walkProps(props, c => { walkProps(props, c => {
if ((c._instanceName || "").startsWith(capitalised)) { const thisInstanceName = get_capitalised_name(c._instanceName)
matchingComponents.push(c._instanceName) if ((thisInstanceName || "").startsWith(capitalised)) {
matchingComponents.push(thisInstanceName)
} }
}) })
} }

View File

@ -153,20 +153,30 @@ const _saveScreen = async (store, s, screen) => {
return s return s
} }
const createScreen = store => ({ screenName, route, screen }) => { const createScreen = store => ({
screenName,
route,
baseComponent,
screen,
}) => {
store.update(state => { store.update(state => {
const rootComponent = const rootComponent =
state.components["@budibase/standard-components/container"] state.components[
baseComponent || "@budibase/standard-components/container"
]
const newScreen = screen || { const newScreen = screen || {
description: "", description: "",
url: "", url: "",
_css: "", _css: "",
props: createProps(rootComponent).props, props: createProps(rootComponent).props,
route,
} }
newScreen.route = route
newScreen.name = newScreen.props._id newScreen.name = newScreen.props._id
newScreen.props._instanceName = screenName || "" if (screenName) {
newScreen.props._instanceName = screenName
}
state.currentPreviewItem = newScreen state.currentPreviewItem = newScreen
state.currentComponentInfo = newScreen.props state.currentComponentInfo = newScreen.props
state.currentFrontEndType = "screen" state.currentFrontEndType = "screen"

View File

@ -1,8 +0,0 @@
export default function(models) {
return models.map(model => ({
name: `Edit ${model.name}`,
create: () => createScreen(model),
}))
}
const createScreen = model => ({})

View File

@ -1,12 +1,22 @@
import editRecordScreen from "./editRecordScreen" import newRecordScreen from "./newRecordScreen"
import recordDetailScreen from "./recordDetailScreen"
import { generateNewIdsForComponent } from "../../storeUtils" import { generateNewIdsForComponent } from "../../storeUtils"
import { uuid } from "builderStore/uuid"
const allTemplates = models => [...editRecordScreen(models)] const allTemplates = models => [
...newRecordScreen(models),
...recordDetailScreen(models),
]
// allows us to apply common behaviour to all create() functions // allows us to apply common behaviour to all create() functions
const createTemplateOverride = (frontendState, create) => () => { const createTemplateOverride = (frontendState, create) => () => {
const screen = create() const screen = create()
generateNewIdsForComponent(screen.props, frontendState) for (let component in screen.props.children) {
generateNewIdsForComponent(component, frontendState)
}
screen.props._id = uuid()
screen.name = screen.props._id
screen.route = screen.route.toLowerCase()
return screen return screen
} }

View File

@ -0,0 +1,44 @@
export default function(models) {
return models.map(model => ({
name: `New ${model.name}`,
create: () => createScreen(model),
}))
}
const createScreen = model => ({
props: {
_id: "f684460e-1f79-42b4-8ffd-1f708bca93ed",
_component: "@budibase/standard-components/container",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
className: "",
onLoad: [],
type: "div",
_children: [
{
_id: "7d1d6b43-b444-46a5-a75c-267fd6b5baf6",
_component: "@budibase/standard-components/heading",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
text: `Create New ${model.name}`,
type: "h1",
_instanceId: "inst_cf8ace4_69efc0d72e6f443db2d4c902c14d9394",
_instanceName: `Heading 1`,
_children: [],
},
],
_instanceName: `New ${model.name}`,
},
route: `/${model.name}/new`,
name: "screen-id",
})

View File

@ -0,0 +1,44 @@
export default function(models) {
return models.map(model => ({
name: `New ${model.name}`,
create: () => createScreen(model),
}))
}
const createScreen = model => ({
props: {
_id: "f684460e-1f79-42b4-8ffd-1f708bca93ed",
_component: "@budibase/standard-components/recorddetail",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
className: "",
onLoad: [],
type: "div",
_children: [
{
_id: "7d1d6b43-b444-46a5-a75c-267fd6b5baf6",
_component: "@budibase/standard-components/heading",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_code: "",
className: "",
text: `${model.name} Detail`,
type: "h1",
_instanceId: "inst_cf8ace4_69efc0d72e6f443db2d4c902c14d9394",
_instanceName: `Heading 1`,
_children: [],
},
],
_instanceName: `${model.name} Detail`,
},
route: `/${model.name}/new`,
name: "screen-id",
})

View File

@ -69,18 +69,8 @@
} }
const copyComponent = () => { const copyComponent = () => {
store.update(s => { storeComponentForCopy(false)
const parent = getParent(s.currentPreviewItem.props, component) pasteComponent("below")
const copiedComponent = cloneDeep(component)
walkProps(copiedComponent, p => {
p._id = uuid()
})
parent._children = [...parent._children, copiedComponent]
saveCurrentPreviewItem(s)
s.currentComponentInfo = copiedComponent
regenerateCssForCurrentScreen(s)
return s
})
} }
const deleteComponent = () => { const deleteComponent = () => {

View File

@ -2,6 +2,7 @@
import { store, backendUiStore } from "builderStore" import { store, backendUiStore } from "builderStore"
import { Input, Select, Button, Spacer } from "@budibase/bbui" import { Input, Select, Button, Spacer } from "@budibase/bbui"
import getTemplates from "builderStore/store/screenTemplates" import getTemplates from "builderStore/store/screenTemplates"
import { createEventDispatcher } from "svelte"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let screens let screens
@ -35,9 +36,11 @@
<Select bind:value={template} secondary> <Select bind:value={template} secondary>
<option value="">Choose an Option</option> <option value="">Choose an Option</option>
<option value="none">No Template</option> <option value="none">No Template</option>
{#each templates as templates} {#if templates}
<option value={template}>{template.name}</option> {#each templates as template}
{/each} <option value={template}>{template.name}</option>
{/each}
{/if}
</Select> </Select>
</div> </div>
</div> </div>

View File

@ -9,6 +9,11 @@
dialog.show() dialog.show()
} }
const finished = () => {
dialog.hide()
template = undefined
}
let dialog let dialog
let template let template
</script> </script>
@ -19,12 +24,12 @@
{#if template === 'none'} {#if template === 'none'}
<div transition:slide={{ delay: 0, duration: 300 }}> <div transition:slide={{ delay: 0, duration: 300 }}>
<NoTemplate on:finished={dialog.hide} /> <NoTemplate on:finished={finished} />
</div> </div>
{:else} {:else}
<div transition:fade={{ delay: 100, duration: 200 }}> <div transition:fade={{ delay: 0, duration: 100 }}>
<ChooseTemplate <ChooseTemplate
on:finished={dialog.hide} on:finished={finished}
on:next={() => (template = 'none')} /> on:next={() => (template = 'none')} />
</div> </div>
{/if} {/if}

View File

@ -1,17 +1,23 @@
<script> <script>
import { store } from "builderStore" import { store } from "builderStore"
import { Input, Button, Spacer } from "@budibase/bbui" import { Input, Button, Spacer, Select } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { some } from "lodash/fp" import { some } from "lodash/fp"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const CONTAINER = "@budibase/standard-components/container"
let screens let screens
let name = "" let name = ""
let routeError let routeError
let baseComponent = CONTAINER
$: route = !route && $store.screens.length === 0 ? "*" : route $: route = !route && $store.screens.length === 0 ? "*" : route
$: baseComponents = Object.values($store.components)
.filter(componentDefinition => componentDefinition.baseComponent)
.map(c => c._component)
const save = () => { const save = () => {
if (!route) { if (!route) {
routeError = "Url is required" routeError = "Url is required"
@ -28,10 +34,12 @@
store.createScreen({ store.createScreen({
screenName: name, screenName: name,
route, route,
baseComponent,
}) })
name = "" name = ""
route = "" route = ""
baseComponent = CONTAINER
dispatch("finished") dispatch("finished")
} }
@ -50,9 +58,18 @@
route = "/" + event.target.value route = "/" + event.target.value
} }
} }
const componentShortName = fullname => {
const parts = fullname.split("/")
const shortName = parts[parts.length - 1]
// make known ones a bit prettier
if (shortName === "container") return "Container"
if (shortName === "recorddetail") return "Record Detail"
if (shortName === "newrecord") return "New Record"
return shortName
}
</script> </script>
<h2>New Screen</h2>
<Spacer extraLarge /> <Spacer extraLarge />
<div data-cy="new-screen-dialog"> <div data-cy="new-screen-dialog">
@ -68,6 +85,15 @@
on:change={routeChanged} /> on:change={routeChanged} />
</div> </div>
<div class="bb-margin-xl">
<label>Base Component</label>
<Select bind:value={baseComponent} secondary>
{#each baseComponents as component}
<option value={component}>{componentShortName(component)}</option>
{/each}
</Select>
</div>
</div> </div>
<Spacer extraLarge /> <Spacer extraLarge />

View File

@ -274,6 +274,17 @@
"context": "model", "context": "model",
"children": true, "children": true,
"data": true, "data": true,
"baseComponent": true,
"props": {
"model": "models"
}
},
"newrecord": {
"description": "Loads a record, using an ID in the url",
"context": "model",
"children": true,
"data": true,
"baseComponent": true,
"props": { "props": {
"model": "models" "model": "models"
} }
@ -715,7 +726,7 @@
"default": "div" "default": "div"
} }
}, },
"container": true, "baseComponent": true,
"tags": [ "tags": [
"div", "div",
"container", "container",