Merge pull request #110 from shogunpurple/presets

Presets
This commit is contained in:
Martin McKeaveney 2020-02-18 20:46:25 +00:00 committed by GitHub
commit b8bd724dbf
46 changed files with 363 additions and 1214 deletions

View File

@ -1,24 +1,5 @@
{
"_lib": "./dist/index.js",
"_generators": {
"_lib": "./dist/generators.js",
"app": {
"name": "App",
"description": "Generate app based on your backend"
},
"forms": {
"name": "Forms",
"description": "Generate forms, based on your records"
},
"indexTables": {
"name": "Index Tables",
"description": "Generate a table based on an index"
},
"recordHomepages": {
"name": "Record Homepage",
"description": "Generates a 'homepage' based on your record types, including a create/edit form. Selecting a nav item will display a root content"
}
},
"form" : {
"importPath": "Form",
"name": "Form",

View File

@ -4,7 +4,7 @@
"main": "dist/index.js",
"module": "dist/index.js",
"scripts": {
"build": "rollup -c && rollup -c rollup.generatorsconfig.js",
"build": "rollup -c",
"prepublishOnly": "npm run build",
"testbuild": "rollup -w -c rollup.testconfig.js",
"dev": "run-p start:dev testbuild",

View File

@ -1,14 +0,0 @@
import resolve from "rollup-plugin-node-resolve"
export default {
input: "src/generators.js",
output: [
{
file: "dist/generators.js",
format: "esm",
name: "budibaseStandardComponents",
sourcemap: "inline",
},
],
plugins: [resolve()],
}

View File

@ -5,12 +5,10 @@ const { join, basename } = require("path")
const packagesFolder = ".."
const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join(packagesFolder, "server", "appPackages")
@ -69,7 +67,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile)
for (let app of apps) {
@ -77,16 +74,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(join(publicUnauth(app), "dist"))
await copyGenerators(join(publicUnauth(app), "dist"))
}
})()

View File

@ -1,4 +0,0 @@
export { forms } from "./generators/formsGenerator"
export { indexTables } from "./generators/indexTablesGenerator"
export { app } from "./generators/appGenerator"
export { recordHomePageComponents as recordHomepages } from "./generators/recordHomePageGenerator"

View File

@ -1,37 +0,0 @@
import {
navContentComponentName,
selectNavContent,
} from "./selectedNavContentGenerator"
import { recordHomepages } from "./recordHomePageGenerator"
export const app = ({ records, indexes, helpers }) => [
{
name: "Application Root",
inherits: "@budibase/bootstrap-components/nav",
props: {
items: recordHomepages({ indexes, records }).map(navItem),
orientation: "horizontal",
alignment: "start",
fill: false,
pills: true,
selectedItem: {
"##bbstate": "selectedNav",
"##bbstatefallback": `${records[0].name}`,
"##bbsource": "store",
},
className: "p-3",
},
},
{
name: "Login",
inherits: "@budibase/standard-components/login",
props: {},
},
...selectNavContent({ records, indexes, helpers }),
]
export const navItem = ({ record }) => ({
title: record.collectionName,
component: {
_component: navContentComponentName(record),
},
})

View File

@ -1,18 +0,0 @@
export const buttons = () => [
{
name: "common/Primary Button",
description: "Bootstrap primary button ",
inherits: "@budibase/standard-components/button",
props: {
className: "btn btn-primary",
},
},
{
name: "common/Default Button",
description: "Bootstrap default button",
inherits: "@budibase/standard-components/button",
props: {
className: "btn btn-secondary",
},
},
]

View File

@ -1,128 +0,0 @@
import { buttons } from "./buttonGenerators"
export const forms = ({ records, indexes, helpers }) => [
...records.map(root),
...buttons({ records, indexes, helpers }),
]
export const formName = record => `${record.name}/${record.name} Form`
const root = record => ({
name: formName(record),
description: `Control for creating/updating '${record.nodeKey()}' `,
inherits: "@budibase/standard-components/container",
props: {
className: "p-1",
children: [
{
component: {
_component: "@budibase/standard-components/h3",
text: `Edit ${record.name}`,
},
},
form(record),
saveCancelButtons(record),
],
},
})
const form = record => ({
component: {
_component: "@budibase/standard-components/form",
formControls: record.fields.map(f => formControl(record, f)),
},
})
const formControl = (record, field) => {
if (
field.type === "string" &&
field.typeOptions.values &&
field.typeOptions.values.length > 0
) {
return {
control: {
_component: "@budibase/standard-components/select",
options: field.typeOptions.values.map(v => ({ id: v, value: v })),
value: {
"##bbstate": `${record.name}.${field.name}`,
"##bbsource": "store",
},
className: "form-control",
},
label: field.label,
}
} else {
return {
control: {
_component: "@budibase/standard-components/input",
value: {
"##bbstate": `${record.name}.${field.name}`,
"##bbsource": "store",
},
className: "form-control",
type:
field.type === "string"
? "text"
: field.type === "datetime"
? "date"
: field.type === "number"
? "number"
: "text",
},
label: field.label,
}
}
}
const saveCancelButtons = record => ({
component: {
_component: "@budibase/standard-components/stackpanel",
direction: "horizontal",
children: [
paddedPanelForButton({
_component: "common/Primary Button",
contentText: `Save ${record.name}`,
onClick: [
{
"##eventHandlerType": "Save Record",
parameters: {
statePath: `${record.name}`,
},
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "",
},
},
],
}),
paddedPanelForButton({
_component: "common/Default Button",
contentText: `Cancel`,
onClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "",
},
},
],
}),
],
},
})
const paddedPanelForButton = button => ({
control: {
_component: "@budibase/standard-components/container",
className: "btn-group",
children: [
{
component: button,
},
],
},
})

View File

@ -1,14 +0,0 @@
export const getRecordPath = () => {
const parts = []
const add = current => {
parts.push(current.name)
if (current.parent().type === "root") {
return
}
add(current.parent())
}
return parts.reverse().join("/")
}

View File

@ -1,53 +0,0 @@
import { getRecordPath } from "./getRecordPath"
export const indexTables = ({ indexes, helpers }) =>
indexes.map(i => indexTable(i, helpers))
const excludedColumns = ["id", "isNew", "key", "type", "sortKey"]
export const indexTableProps = (index, helpers) => ({
data: {
"##bbstate": index.nodeKey(),
"##bbsource": "store",
},
tableClass: "table table-hover",
theadClass: "thead-dark",
columns: helpers
.indexSchema(index)
.filter(c => !excludedColumns.includes(c.name))
.map(column),
onRowClick: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `selectedrow_${index.name}`,
value: {
"##bbstate": "key",
"##bbsource": "event",
},
},
},
],
})
export const getIndexTableName = (index, record) => {
record = record || index.parent().type === "record" ? index.parent() : null
return record
? `${getRecordPath(record)}/${index.name} Table`
: `${index.name} Table`
}
const indexTable = (index, helpers) => ({
name: getIndexTableName(index),
inherits: "@budibase/standard-components/table",
props: indexTableProps(index, helpers),
})
const column = col => ({
title: col.name,
value: {
"##bbstate": col.name,
"##bbsource": "context",
},
})

View File

@ -1,183 +0,0 @@
import { getIndexTableName, indexTables } from "./indexTablesGenerator"
import { buttons } from "./buttonGenerators"
export const recordHomePageComponents = ({ indexes, records, helpers }) => [
...recordHomepages({ indexes, records }).map(component),
...recordHomepages({ indexes, records }).map(homePageButtons),
...indexTables({ indexes, records, helpers }),
...buttons({ indexes, buttons, helpers }),
]
const findIndexForRecord = (indexes, record) => {
const forRecord = indexes.filter(i =>
i.allowedRecordNodeIds.includes(record.nodeId)
)
if (forRecord.length === 0) return
if (forRecord.length === 1) return forRecord[0]
const noMap = forRecord.filter(i => !i.filter || !i.filter.trim())
if (noMap.length === 0) forRecord[0]
return noMap[0]
}
export const recordHomepages = ({ indexes, records }) =>
records
.filter(r => r.parent().type === "root")
.map(r => ({
record: r,
index: findIndexForRecord(indexes, r),
}))
.filter(r => r.index)
export const homepageComponentName = record =>
`${record.name}/${record.name} homepage`
const component = ({ record, index }) => ({
inherits: "@budibase/standard-components/container",
name: homepageComponentName(record),
props: {
className: "d-flex flex-column h-100",
children: [
{
component: {
_component: `${record.name}/homepage buttons`,
},
},
{
component: {
_component: getIndexTableName(index),
},
className: "flex-gow-1 overflow-auto",
},
],
onLoad: [
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "",
},
},
{
"##eventHandlerType": "List Records",
parameters: {
statePath: index.nodeKey(),
indexKey: index.nodeKey(),
},
},
],
},
})
const homePageButtons = ({ index, record }) => ({
inherits: "@budibase/standard-components/container",
name: `${record.name}/homepage buttons`,
props: {
className: "btn-toolbar mt-4 mb-2",
children: [
{
component: {
_component: "@budibase/standard-components/container",
className: "btn-group mr-3",
children: [
{
component: {
_component: "common/Default Button",
contentText: `Create ${record.name}`,
onClick: [
{
"##eventHandlerType": "Get New Record",
parameters: {
statePath: record.name,
collectionKey: `/${record.collectionName}`,
childRecordType: record.name,
},
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "true",
},
},
],
},
},
{
component: {
_component: "common/Default Button",
contentText: `Refresh`,
onClick: [
{
"##eventHandlerType": "List Records",
parameters: {
statePath: index.nodeKey(),
indexKey: index.nodeKey(),
},
},
],
},
},
],
},
},
{
component: {
_component: "@budibase/standard-components/if",
condition: `$store.selectedrow_${index.name} && $store.selectedrow_${index.name}.length > 0`,
thenComponent: {
_component: "@budibase/standard-components/container",
className: "btn-group",
children: [
{
component: {
_component: "common/Default Button",
contentText: `Edit ${record.name}`,
onClick: [
{
"##eventHandlerType": "Load Record",
parameters: {
statePath: record.name,
recordKey: {
"##bbstate": `selectedrow_${index.name}`,
"##source": "store",
},
},
},
{
"##eventHandlerType": "Set State",
parameters: {
path: `isEditing${record.name}`,
value: "true",
},
},
],
},
},
{
component: {
_component: "common/Default Button",
contentText: `Delete ${record.name}`,
onClick: [
{
"##eventHandlerType": "Delete Record",
parameters: {
recordKey: {
"##bbstate": `selectedrow_${index.name}`,
"##source": "store",
},
},
},
],
},
},
],
},
},
},
],
},
})

View File

@ -1,32 +0,0 @@
import {
recordHomepages,
homepageComponentName,
recordHomePageComponents,
} from "./recordHomePageGenerator"
import { formName, forms } from "./formsGenerator"
export const selectNavContent = ({ indexes, records, helpers }) => [
...recordHomepages({ indexes, records }).map(component),
...recordHomePageComponents({ indexes, records, helpers }),
...forms({ indexes, records, helpers }),
]
export const navContentComponentName = record =>
`${record.name}/${record.name} Nav Content`
const component = ({ record }) => ({
inherits: "@budibase/standard-components/if",
description: `the component that gets displayed when the ${record.collectionName} nav is selected`,
name: navContentComponentName(record),
props: {
condition: `$store.isEditing${record.name}`,
thenComponent: {
_component: formName(record),
},
elseComponent: {
_component: homepageComponentName(record),
},
},
})

View File

@ -19,8 +19,7 @@ const _builderProxy = proxy("/_builder", {
const apiProxy = proxy(
[
"/_builder/api/**",
"/_builder/**/componentlibrary",
"/_builder/**/componentlibraryGenerators",
"/_builder/**/componentlibrary"
],
{
target,

View File

@ -1,5 +1,3 @@
import { map } from "lodash/fp"
export const loadLibs = async (appName, appPackage) => {
const allLibraries = {}
for (let lib of appPackage.pages.componentLibraries) {
@ -10,16 +8,6 @@ export const loadLibs = async (appName, appPackage) => {
return allLibraries
}
export const loadGeneratorLibs = async (appName, appPackage) => {
const allGeneratorLibs = {}
for (let lib of appPackage.pages.componentLibraries) {
const generatorModule = await import(makeGeneratorLibraryUrl(appName, lib))
allGeneratorLibs[lib] = generatorModule
}
return allGeneratorLibs
}
export const loadLibUrls = (appName, appPackage) => {
const allLibraries = []
for (let lib of appPackage.pages.componentLibraries) {
@ -35,13 +23,5 @@ export const loadLib = async (appName, lib, allLibs) => {
return allLibs
}
export const loadGeneratorLib = async (appName, lib, allGeneratorLibs) => {
allGeneratorLibs[lib] = await import(makeGeneratorLibraryUrl(appName, lib))
return allGeneratorLibs
}
export const makeLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibrary?lib=${encodeURI(lib)}`
export const makeGeneratorLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibraryGenerators?lib=${encodeURI(lib)}`

View File

@ -35,13 +35,10 @@ import {
import { expandComponentDefinition } from "../userInterface/pagesParsing/types"
import {
loadLibs,
loadLibUrls,
loadGeneratorLibs,
loadLibUrls
} from "./loadComponentLibraries"
import { buildCodeForScreens } from "./buildCodeForScreens"
import { generate_screen_css } from "./generate_css"
import { insertCodeMetadata } from "./insertCodeMetadata"
// import { uuid } from "./uuid"
let appname = ""
@ -94,7 +91,6 @@ export const getStore = () => {
store.deleteLevel = deleteLevel(store)
store.setActiveNav = setActiveNav(store)
store.saveScreen = saveScreen(store)
store.refreshComponents = refreshComponents(store)
store.addComponentLibrary = addComponentLibrary(store)
store.renameScreen = renameScreen(store)
store.deleteScreen = deleteScreen(store)
@ -159,8 +155,6 @@ const initialise = (store, initial) => async () => {
}
initial.libraries = await loadLibs(appname, pkg)
initial.generatorLibraries = await loadGeneratorLibs(appname, pkg)
initial.loadLibraryUrls = () => loadLibUrls(appname, pkg)
initial.appname = appname
initial.pages = pkg.pages
@ -168,7 +162,6 @@ const initialise = (store, initial) => async () => {
initial.hierarchy = pkg.appDefinition.hierarchy
initial.accessLevels = pkg.accessLevels
initial.screens = values(pkg.screens)
initial.generators = generatorsArray(pkg.components.generators)
initial.components = values(pkg.components.components).map(
expandComponentDefinition
)
@ -187,9 +180,6 @@ const initialise = (store, initial) => async () => {
return initial
}
const generatorsArray = generators =>
pipe(generators, [keys, filter(k => k !== "_lib"), map(k => generators[k])])
const showSettings = store => () => {
store.update(s => {
s.showSettings = !s.showSettings
@ -683,27 +673,6 @@ const removeStylesheet = store => stylesheet => {
})
}
const refreshComponents = store => async () => {
const componentsAndGenerators = await api
.get(`/_builder/api/${appname}/components`)
.then(r => r.json())
const components = pipe(componentsAndGenerators.components, [
keys,
map(k => ({ ...componentsAndGenerators[k], name: k })),
map(c => expandComponentDefinition(c)),
])
store.update(s => {
s.components = pipe(s.components, [
filter(c => !isRootComponent(c)),
concat(components),
])
s.generators = componentsAndGenerators.generators
return s
})
}
const _savePage = async s => {
const page = s.pages[s.currentPageName]
@ -749,19 +718,25 @@ const setCurrentPage = store => pageName => {
const getContainerComponent = components =>
components.find(c => c.name === "@budibase/standard-components/container")
const addChildComponent = store => componentName => {
store.update(s => {
const component = componentName.startsWith("##")
? getBuiltin(componentName)
: s.components.find(c => c.name === componentName)
const newComponent = createProps(component)
/**
* @param {string} componentToAdd - name of the component to add to the application
* @param {string} presetName - name of the component preset if defined
*/
const addChildComponent = store => (componentToAdd, presetName) => {
store.update(state => {
const component = componentToAdd.startsWith("##")
? getBuiltin(componentToAdd)
: state.components.find(({ name }) => name === componentToAdd)
const presetProps = presetName ? component.presets[presetName] : {};
const newComponent = createProps(component, presetProps);
s.currentComponentInfo._children = s.currentComponentInfo._children.concat(
state.currentComponentInfo._children = state.currentComponentInfo._children.concat(
newComponent.props
)
_savePage(s)
return s
_savePage(state)
return state
})
}

View File

@ -1,4 +1,8 @@
<button on:click>+</button>
<button on:click>
<slot>
+
</slot>
</button>
<style>
button {
@ -8,8 +12,8 @@
border-radius: 5px;
background: rgba(249, 249, 249, 1);
width: 1.8rem;
height: 1.8rem;
min-width: 1.8rem;
min-height: 1.8rem;
padding-bottom: 10px;
display: flex;

View File

@ -0,0 +1,218 @@
<script>
import { splitName } from "./pagesParsing/splitRootComponentName.js"
import { store } from "../builderStore"
import { find, sortBy } from "lodash/fp"
import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/"
import Select from "../common/Select.svelte"
import Button from "../common/PlusButton.svelte"
let componentLibraries = []
let current_view = "text"
let selectedComponent = null
const addRootComponent = (component, allComponents) => {
const { libName } = splitName(component.name)
let group = find(r => r.libName === libName)(allComponents)
if (!group) {
group = {
libName,
components: [],
}
allComponents.push(group)
}
group.components.push(component)
}
const onComponentChosen = store.addChildComponent
$: {
const newComponentLibraries = []
for (let comp of sortBy(["name"])($store.components)) {
addRootComponent(comp, newComponentLibraries)
}
componentLibraries = newComponentLibraries
}
</script>
<div class="root">
<Select>
{#each componentLibraries as componentLibrary}
<option value={componentLibrary.libName}>
{componentLibrary.libName}
</option>
{/each}
</Select>
{#each componentLibraries as componentLibrary}
<div class="library-container">
<ul>
<li>
<button
class:selected={current_view === 'text'}
on:click={() => (current_view = 'text')}>
<InputIcon />
</button>
</li>
<li>
<button
class:selected={current_view === 'layout'}
on:click={() => (current_view = 'layout')}>
<LayoutIcon />
</button>
</li>
<li>
<button
class:selected={current_view === 'media'}
on:click={() => (current_view = 'media')}>
<ImageIcon />
</button>
</li>
</ul>
{#each $store.builtins.concat(componentLibrary.components) as component}
<div class="component-container">
<div
class="component"
on:click={() => onComponentChosen(component.name)}>
<div class="name">{splitName(component.name).componentName}</div>
{#if component.presets && component.name === selectedComponent}
<ul class="preset-menu">
<span>{splitName(component.name).componentName} Presets</span>
{#each Object.keys(component.presets) as preset}
<li
on:click|stopPropagation={() => onComponentChosen(component.name, preset)}>
{preset}
</li>
{/each}
</ul>
{/if}
</div>
{#if component.presets}
<Button
on:click={() => {
selectedComponent = selectedComponent ? null : component.name
}}>
<span
class="open-presets"
class:open={selectedComponent === component.name}>
...
</span>
</Button>
{/if}
</div>
{/each}
</div>
{/each}
</div>
<style>
.root {
display: flex;
flex-direction: column;
}
.library-container {
padding: 0 0 10px 10px;
flex: 1 1 auto;
min-height: 0px;
}
.component-container {
display: flex;
align-items: center;
}
.component {
position: relative;
padding: 0 15px;
cursor: pointer;
border: 1px solid #ebebeb;
border-radius: 2px;
margin: 10px 0;
height: 40px;
box-sizing: border-box;
color: #163057;
display: flex;
align-items: center;
flex: 1;
margin-right: 5px;
}
.component:hover {
background-color: var(--lightslate);
}
.component > .name {
color: #163057;
display: inline-block;
font-size: 12px;
font-weight: bold;
opacity: 0.6;
}
ul {
list-style: none;
display: flex;
padding: 0;
}
.preset-menu {
flex-direction: column;
position: absolute;
top: 25px;
left: 0;
right: 0;
z-index: 1;
background: #fafafa;
padding: 10px;
border-radius: 2px;
color: rgba(22, 48, 87, 0.6);
}
.preset-menu > span {
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
}
.preset-menu li {
font-size: 14px;
margin-top: 13px;
}
.preset-menu li:hover {
font-weight: bold;
}
li {
margin-right: 20px;
background: none;
border-radius: 5px;
}
li button {
width: 100%;
height: 100%;
background: none;
border: none;
border-radius: 5px;
padding: 12px;
outline: none;
cursor: pointer;
}
.selected {
color: var(--button-text);
background: var(--background-button) !important;
}
.open {
color: rgba(0, 85, 255, 1);
}
</style>

View File

@ -1,158 +0,0 @@
<script>
import { splitName } from "./pagesParsing/splitRootComponentName.js"
import { store } from "../builderStore"
import { find, sortBy } from "lodash/fp"
import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/"
let componentLibraries = []
let current_view = "text"
const addRootComponent = (c, all) => {
const { libName } = splitName(c.name)
let group = find(r => r.libName === libName)(all)
if (!group) {
group = {
libName,
components: [],
generators: [],
}
all.push(group)
}
group.components.push(c)
}
const onComponentChosen = store.addChildComponent
$: {
const newComponentLibraries = []
for (let comp of sortBy(["name"])($store.components)) {
addRootComponent(comp, newComponentLibraries)
}
componentLibraries = newComponentLibraries
}
</script>
<div class="root">
{#each componentLibraries as lib}
<div class="library-header">{lib.libName}</div>
<div class="library-container">
<ul>
<li>
<button
class:selected={current_view === 'text'}
on:click={() => (current_view = 'text')}>
<InputIcon />
</button>
</li>
<li>
<button
class:selected={current_view === 'layout'}
on:click={() => (current_view = 'layout')}>
<LayoutIcon />
</button>
</li>
<li>
<button
class:selected={current_view === 'media'}
on:click={() => (current_view = 'media')}>
<ImageIcon />
</button>
</li>
</ul>
{#each $store.builtins.concat(lib.components.filter(_ => true)) as component}
<div
class="component"
on:click={() => onComponentChosen(component.name)}>
<div class="name">{splitName(component.name).componentName}</div>
</div>
{/each}
</div>
{/each}
</div>
<style>
.root {
display: flex;
flex-direction: column;
}
.library-header {
font-size: 1.1em;
border-color: var(--primary25);
border-width: 1px 0px;
border-style: solid;
background-color: var(--primary10);
padding: 5px 0;
flex: 0 0 auto;
}
.library-container {
padding: 0 0 10px 10px;
flex: 1 1 auto;
min-height: 0px;
}
.component {
padding: 0 15px;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 2px;
margin: 10px 0;
height: 40px;
box-sizing: border-box;
color: #163057;
display: flex;
align-items: center;
}
.component:hover {
background-color: var(--lightslate);
}
.component > .name {
color: #163057;
display: inline-block;
font-size: 12px;
font-weight: bold;
opacity: 0.6;
}
ul {
list-style: none;
display: flex;
padding: 0;
}
li {
margin-right: 20px;
background: none;
border-radius: 5px;
width: 48px;
height: 48px;
}
li button {
width: 100%;
height: 100%;
background: none;
border: none;
border-radius: 5px;
padding: 12px;
outline: none;
cursor: pointer;
}
.selected {
color: var(--button-text);
background: var(--background-button) !important;
}
</style>

View File

@ -1,7 +1,7 @@
<script>
import { store } from "../builderStore/"
import ComponentPanel from "./ComponentPanel.svelte"
import ComponentsList from "./ComponentsList.svelte"
import ComponentPropertiesPanel from "./ComponentPropertiesPanel.svelte"
import ComponentSelectionList from "./ComponentSelectionList.svelte"
let selected = "properties"
@ -30,11 +30,11 @@
<div class="panel">
{#if selected === 'properties'}
<ComponentPanel />
<ComponentPropertiesPanel />
{/if}
{#if selected === 'components'}
<ComponentsList />
<ComponentSelectionList />
{/if}
</div>

View File

@ -1,7 +1,6 @@
<script>
import PropsView from "./PropsView.svelte"
import { store } from "../builderStore"
import IconButton from "../common/IconButton.svelte"
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import { LayoutIcon, PaintIcon, TerminalIcon } from "../common/Icons/"

View File

@ -1,5 +1,4 @@
<script>
import ComponentSelector from "./ComponentSelector.svelte"
import { store } from "../builderStore"
import PropsView from "./PropsView.svelte"
import Textbox from "../common/Textbox.svelte"

View File

@ -1,48 +1,50 @@
<script>
import { ArrowDownIcon } from "../common/Icons/";
import { store } from "../builderStore";
import { buildStateOrigins } from "../builderStore/buildStateOrigins";
import { isBinding, getBinding, setBinding } from "../common/binding";
import { ArrowDownIcon } from "../common/Icons/"
import { store } from "../builderStore"
import { buildStateOrigins } from "../builderStore/buildStateOrigins"
import { isBinding, getBinding, setBinding } from "../common/binding"
export let onChanged = () => {};
export let value = "";
export let onChanged = () => {}
export let value = ""
let isOpen = false;
let stateBindings = [];
let isOpen = false
let stateBindings = []
let bindingPath = "";
let bindingFallbackValue = "";
let bindingSource = "store";
let bindingValue = "";
let bindingPath = ""
let bindingFallbackValue = ""
let bindingSource = "store"
let bindingValue = ""
const bind = (path, fallback, source) => {
if (!path) {
onChanged(fallback);
return;
onChanged(fallback)
return
}
const binding = setBinding({ path, fallback, source });
onChanged(binding);
};
const binding = setBinding({ path, fallback, source })
onChanged(binding)
}
const setBindingPath = value =>
bind(value, bindingFallbackValue, bindingSource);
bind(value, bindingFallbackValue, bindingSource)
const setBindingFallback = value => bind(bindingPath, value, bindingSource);
const setBindingFallback = value => bind(bindingPath, value, bindingSource)
const setBindingSource = value =>
bind(bindingPath, bindingFallbackValue, value);
bind(bindingPath, bindingFallbackValue, value)
$: {
const binding = getBinding(value);
if (bindingPath !== binding.path) isOpen = false;
bindingPath = binding.path;
bindingValue = typeof value === "object" ? "" : value;
bindingFallbackValue = binding.fallback || bindingValue;
const binding = getBinding(value)
if (bindingPath !== binding.path) isOpen = false
bindingPath = binding.path
bindingValue = typeof value === "object" ? "" : value
bindingFallbackValue = binding.fallback || bindingValue
const currentScreen = $store.screens.find(
({ name }) => name === $store.currentPreviewItem.name
);
stateBindings = currentScreen ? Object.keys(buildStateOrigins(currentScreen)) : [];
)
stateBindings = currentScreen
? Object.keys(buildStateOrigins(currentScreen))
: []
}
</script>
@ -53,17 +55,19 @@
class="uk-input uk-form-small"
value={bindingFallbackValue || bindingPath}
on:change={e => {
setBindingFallback(e.target.value);
onChanged(e.target.value);
setBindingFallback(e.target.value)
onChanged(e.target.value)
}} />
<button on:click={() => (isOpen = !isOpen)}>
<div
class="icon"
class:highlighted={bindingPath}
style={`transform: rotate(${isOpen ? 0 : 90}deg);`}>
<ArrowDownIcon size={36} />
</div>
</button>
{#if stateBindings.length}
<button on:click={() => (isOpen = !isOpen)}>
<div
class="icon"
class:highlighted={bindingPath}
style={`transform: rotate(${isOpen ? 0 : 90}deg);`}>
<ArrowDownIcon size={36} />
</div>
</button>
{/if}
</div>
{#if isOpen}
<ul class="options">
@ -71,7 +75,7 @@
<li
class:bold={stateBinding === bindingPath}
on:click={() => {
setBindingPath(stateBinding === bindingPath ? null : stateBinding);
setBindingPath(stateBinding === bindingPath ? null : stateBinding)
}}>
{stateBinding}
</li>

View File

@ -24,8 +24,13 @@ export const getNewScreen = (components, rootComponentName, name) => {
}
}
/**
* @param {object} componentDefinition - component definition from a component library
* @param {object} derivedFromProps - extra props derived from a components given props.
* @return {object} the fully created properties for the component, and any property parsing errors
*/
export const createProps = (componentDefinition, derivedFromProps) => {
const error = (propName, error) => errors.push({ propName, error })
const errorOccurred = (propName, error) => errors.push({ propName, error })
const props = {
_component: componentDefinition.name,
@ -37,12 +42,12 @@ export const createProps = (componentDefinition, derivedFromProps) => {
const errors = []
if (!componentDefinition.name)
error("_component", "Component name not supplied")
errorOccurred("_component", "Component name not supplied")
const propsDef = componentDefinition.props
for (let propDef in propsDef) {
const parsedPropDef = parsePropDef(propsDef[propDef])
if (parsedPropDef.error) error(propDef, parsedPropDef.error)
if (parsedPropDef.error) errorOccurred(propDef, parsedPropDef.error)
else props[propDef] = parsedPropDef
}

View File

@ -573,23 +573,6 @@
lodash "^4.17.10"
to-fast-properties "^2.0.0"
"@budibase/core@^0.0.16":
version "0.0.16"
resolved "https://registry.yarnpkg.com/@budibase/core/-/core-0.0.16.tgz#efff16876f906b2aa59803c3312ec7593664b623"
integrity sha512-DvzfurHHp9KkSjkvbGbKsVczR5ne38bMLRA2hHEJxAmC0Tshld06cEq7HMy2BmPb6kaC1URYHlFs/gPhW2cSFQ==
dependencies:
"@nx-js/compiler-util" "^2.0.0"
date-fns "^1.29.0"
lodash "^4.17.13"
lunr "^2.3.5"
safe-buffer "^5.1.2"
shortid "^2.2.8"
"@nx-js/compiler-util@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@nx-js/compiler-util/-/compiler-util-2.0.0.tgz#c74c12165fa2f017a292bb79af007e8fce0af297"
integrity sha512-AxSQbwj9zqt8DYPZ6LwZdytqnwfiOEdcFdq4l8sdjkZmU2clTht7RDLCI8xvkp7KqgcNaOGlTeCM55TULWruyQ==
"@types/body-parser@*":
version "1.17.0"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c"
@ -911,11 +894,6 @@ core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
date-fns@^1.29.0:
version "1.30.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@ -1438,11 +1416,6 @@ loose-envify@^1.0.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lunr@^2.3.5:
version "2.3.8"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072"
integrity sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==
make-dir@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
@ -1556,11 +1529,6 @@ nan@^2.9.2:
version "2.11.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766"
nanoid@^2.1.0:
version "2.1.11"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@ -1946,13 +1914,6 @@ set-value@^2.0.0:
is-plain-object "^2.0.3"
split-string "^3.0.1"
shortid@^2.2.8:
version "2.2.15"
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
integrity sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==
dependencies:
nanoid "^2.1.0"
signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"

View File

@ -1,6 +1,5 @@
{
"_lib": "./dist/index.js",
"_generators": {},
"Body1": {
"name": "Body1",
"description": "Sets the font properties as Roboto Body 1",

View File

@ -1,14 +0,0 @@
import resolve from "rollup-plugin-node-resolve"
export default {
input: "src/generators.js",
output: [
{
file: "dist/generators.js",
format: "esm",
name: "budibaseStandardComponents",
sourcemap: "inline",
},
],
plugins: [resolve()],
}

View File

@ -6,12 +6,10 @@ const serverConfig = require("../../server/config")()
const packagesFolder = ".."
const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join(
packagesFolder,
@ -68,7 +66,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile)
for (let app of apps) {
@ -77,16 +74,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(join(publicUnauth(app), "dist"))
await copyGenerators(join(publicUnauth(app), "dist"))
}
})()

View File

@ -6,12 +6,10 @@ const serverConfig = require("../../../server/config")()
const packagesFolder = ".."
const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join(
packagesFolder,
@ -68,7 +66,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile)
for (let app of apps) {
@ -77,16 +74,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(join(publicUnauth(app), "dist"))
await copyGenerators(join(publicUnauth(app), "dist"))
}
})()

View File

@ -6,7 +6,7 @@ const { resolve } = require("path")
const send = require("koa-send")
const {
getPackageForBuilder,
getComponents,
getComponentDefinitions,
getApps,
saveScreen,
renameScreen,
@ -70,16 +70,6 @@ module.exports = (config, app) => {
)
await send(ctx, info.components._lib || "index.js", { root: info.libDir })
})
.get("/_builder/:appname/componentLibraryGenerators", async ctx => {
const info = await componentLibraryInfo(
config,
ctx.params.appname,
ctx.query.lib
)
await send(ctx, info.generators._lib || "generators.js", {
root: info.libDir,
})
})
.get("/_builder/*", async (ctx, next) => {
if (!config.dev) {
ctx.response.status = StatusCodes.FORBIDDEN
@ -151,7 +141,7 @@ module.exports = (config, app) => {
})
.get("/_builder/api/:appname/components", async ctx => {
try {
ctx.body = getComponents(config, ctx.params.appname, ctx.query.lib)
ctx.body = getComponentDefinitions(config, ctx.params.appname, ctx.query.lib)
ctx.response.status = StatusCodes.OK
} catch (e) {
if (e.status) {
@ -171,15 +161,6 @@ module.exports = (config, app) => {
ctx.body = info.components
ctx.response.status = StatusCodes.OK
})
.get("/_builder/api/:appname/generators", async ctx => {
const info = await componentLibraryInfo(
config,
ctx.params.appname,
ctx.query.lib ? decodeURI(ctx.query.lib) : ""
)
ctx.body = info.generators
ctx.response.status = StatusCodes.OK
})
.post("/_builder/api/:appname/backend", async ctx => {
await saveBackend(
config,

View File

@ -1,6 +1,11 @@
const { readJSON, exists } = require("fs-extra")
const { resolve, join, dirname } = require("path")
/**
* @param {string} appPath - budibase application name
* @param {string} libname - component library name
* @returns {string} directory name of component definitions for a specific budibase application.
*/
const getLibDir = (appPath, libname) => {
try {
const componentsFile = require.resolve(join(libname, "components.json"), {
@ -17,11 +22,18 @@ const getComponentsFilepath = libPath => resolve(libPath, "components.json")
module.exports.componentsFilepath = (appPath, libname) =>
getComponentsFilepath(getLibDir(appPath, libname))
/**
* @param {string} appPath - the path to a budibase application
* @param {string} libname - the name of the component libary to use for namespacing
* @returns {object} tree of components namespaced by their component library name.
*/
module.exports.componentLibraryInfo = async (appPath, libname) => {
const libDir = getLibDir(appPath, libname)
const componentsPath = getComponentsFilepath(libDir)
if (!(await exists(componentsPath))) {
const componentDefinitionExists = await exists(componentsPath);
if (!componentDefinitionExists) {
const e = new Error(
`could not find components definition file at ${componentsPath}`
)
@ -30,29 +42,17 @@ module.exports.componentLibraryInfo = async (appPath, libname) => {
}
try {
const components = await readJSON(componentsPath)
const namespacedComponents = { _lib: components._lib }
for (let cname in components) {
if (cname === "_lib" || cname == "_generators") continue
const namespacedName = `${libname}/${cname}`
components[cname].name = namespacedName
namespacedComponents[namespacedName] = components[cname]
}
const namespacedGenerators = {}
if (components._generators) {
namespacedGenerators._lib = components._generators._lib || "generators.js"
for (let gname in components._generators) {
if (gname === "_lib") continue
const namespacedName = `${libname}/${gname}`
components._generators[gname].name = namespacedName
namespacedGenerators[namespacedName] = components._generators[gname]
}
const componentDefinitions = await readJSON(componentsPath)
const namespacedComponents = { _lib: componentDefinitions._lib }
for (let componentKey in componentDefinitions) {
if (componentKey === "_lib") continue
const namespacedName = `${libname}/${componentKey}`
componentDefinitions[componentKey].name = namespacedName
namespacedComponents[namespacedName] = componentDefinitions[componentKey]
}
return {
components: namespacedComponents,
generators: namespacedGenerators,
libDir,
componentsPath,
}

View File

@ -39,7 +39,7 @@ module.exports.getPackageForBuilder = async (config, appname) => {
pages,
components: await getComponents(appPath, pages),
components: await getComponentDefinitions(appPath, pages),
}
}
@ -112,36 +112,39 @@ module.exports.savePage = async (config, appname, pagename, page) => {
await buildPage(config, appname, appDefinition, pagename, page)
}
module.exports.componentLibraryInfo = async (config, appname, lib) => {
module.exports.componentLibraryInfo = async (config, appname, componentLibrary) => {
const appPath = appPackageFolder(config, appname)
return await componentLibraryInfo(appPath, lib)
return await componentLibraryInfo(appPath, componentLibrary)
}
const getComponents = async (appPath, pages, lib) => {
let libs
if (!lib) {
/**
* @param {string} appPath - path to a budibase application
* @param {Array} pages - a list of budibase application pages
* @param {string} componentLibrary - component library to fetch components for
* @returns {object} - an object containing component definitions namespaced by their component library
*/
const getComponentDefinitions = async (appPath, pages, componentLibrary) => {
let componentLibraries
if (!componentLibrary) {
pages = pages || (await getPages(appPath))
if (!pages) return []
libs = $(pages, [values, map(p => p.componentLibraries), flatten])
componentLibraries = $(pages, [values, map(p => p.componentLibraries), flatten])
} else {
libs = [lib]
componentLibraries = [componentLibrary]
}
const components = {}
const generators = {}
for (let l of libs) {
const info = await componentLibraryInfo(appPath, l)
for (let library of componentLibraries) {
const info = await componentLibraryInfo(appPath, library)
merge(components, info.components)
merge(generators, info.generators)
}
if (components._lib) delete components._lib
if (components._generators) delete components._generators
return { components, generators }
return { components }
}
module.exports.getComponents = getComponents
module.exports.getComponentDefinitions = getComponentDefinitions

View File

@ -131,29 +131,6 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@budibase/client@^0.0.16":
version "0.0.16"
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.0.16.tgz#4eef9373816448e99cafd2714f417c6610af5e69"
integrity sha512-fx4ptePj7+IehM37xdNPHdu5jEUgAFmDx23jI0yb4sI6Z5U4gxH10FZYyoJ/A9KdzmShsIfgrmudV5ffvoehdg==
dependencies:
"@nx-js/compiler-util" "^2.0.0"
lodash "^4.17.15"
lunr "^2.3.5"
shortid "^2.2.8"
svelte "^3.9.2"
"@budibase/core@^0.0.16":
version "0.0.16"
resolved "https://registry.yarnpkg.com/@budibase/core/-/core-0.0.16.tgz#efff16876f906b2aa59803c3312ec7593664b623"
integrity sha512-DvzfurHHp9KkSjkvbGbKsVczR5ne38bMLRA2hHEJxAmC0Tshld06cEq7HMy2BmPb6kaC1URYHlFs/gPhW2cSFQ==
dependencies:
"@nx-js/compiler-util" "^2.0.0"
date-fns "^1.29.0"
lodash "^4.17.13"
lunr "^2.3.5"
safe-buffer "^5.1.2"
shortid "^2.2.8"
"@cnakazawa/watch@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
@ -322,11 +299,6 @@
path-to-regexp "^1.1.1"
urijs "^1.19.0"
"@nx-js/compiler-util@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@nx-js/compiler-util/-/compiler-util-2.0.0.tgz#c74c12165fa2f017a292bb79af007e8fce0af297"
integrity sha512-AxSQbwj9zqt8DYPZ6LwZdytqnwfiOEdcFdq4l8sdjkZmU2clTht7RDLCI8xvkp7KqgcNaOGlTeCM55TULWruyQ==
"@types/babel__core@^7.1.0":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f"
@ -1073,11 +1045,6 @@ data-urls@^1.0.0:
whatwg-mimetype "^2.2.0"
whatwg-url "^7.0.0"
date-fns@^1.29.0:
version "1.30.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -2785,7 +2752,7 @@ lodash.sortby@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15:
lodash@^4.17.11, lodash@^4.17.13:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@ -2810,11 +2777,6 @@ lru-cache@^4.0.1:
pseudomap "^1.0.2"
yallist "^2.1.2"
lunr@^2.3.5:
version "2.3.8"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072"
integrity sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==
make-dir@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
@ -2976,11 +2938,6 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
nanoid@^2.1.0:
version "2.1.11"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@ -3816,13 +3773,6 @@ shellwords@^0.1.1:
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
shortid@^2.2.8:
version "2.2.15"
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
integrity sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==
dependencies:
nanoid "^2.1.0"
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@ -4100,11 +4050,6 @@ supports-color@^6.1.0:
dependencies:
has-flag "^3.0.0"
svelte@^3.9.2:
version "3.18.2"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.18.2.tgz#f136b9e169049f8bb6a364bd8b8f3b619ed957d9"
integrity sha512-jRk7jdYULb9V4Z+0BKlfofombmdIIQph4leojrOSHzvZBRmCredz7fZsJBiUDLO6h83XYekuLbwfy5zx1i95GQ==
symbol-tree@^3.2.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"

View File

@ -1,32 +1,5 @@
{
"_lib": "./dist/index.js",
"_generators": {
"_lib": "./dist/generators.js",
"app": {
"name": "App",
"description": "Generate app based on your backend"
},
"forms": {
"name": "Forms",
"description": "Generate forms, based on your records"
},
"buttons": {
"name": "Buttons",
"description": "Generate some styled buttons"
},
"headers": {
"name": "Headers",
"description": "Generate some styled headings"
},
"nav": {
"name": "Nav bar",
"description": "Generate a nav bar, based n your root records"
},
"indexTables": {
"name": "Nav bar",
"description": "Generate a table based on an index"
}
},
"button" : {
"name": "Button",
"description": "an html <button />",
@ -43,7 +16,28 @@
"hoverBackground": "string",
"hoverBorder": "string"
},
"tags": ["layout"]
"tags": ["layout"],
"presets": {
"primary": {
"contentText": "Primary Button Preset",
"color": "papayawhip",
"padding": "20px",
"background": "blue"
},
"secondary": {
"contentText": "Secondary Button Preset",
"color": "rebeccapurple",
"padding": "10px",
"background": "#fff",
"border": "1px solid red"
},
"error": {
"contentText": "ERROR",
"color": "red",
"padding": "10px",
"border": "1px solid red"
}
}
},
"login" : {
"name": "Login Control",

View File

@ -4,7 +4,7 @@
"main": "dist/index.js",
"module": "dist/index.js",
"scripts": {
"build": "rollup -c && rollup -c rollup.generatorsconfig.js",
"build": "rollup -c",
"prepublishOnly": "npm run build",
"testbuild": "rollup -w -c rollup.testconfig.js",
"dev": "run-p start:dev testbuild",

View File

@ -27513,7 +27513,7 @@ var app = (function (crypto$1) {
var main = "dist/index.js";
var module = "dist/index.js";
var scripts = {
build: "rollup -c && rollup -c rollup.generatorsconfig.js",
build: "rollup -c",
prepublishOnly: "npm run build",
testbuild: "rollup -w -c rollup.testconfig.js",
dev: "run-p start:dev testbuild",

View File

@ -1,14 +0,0 @@
import resolve from "rollup-plugin-node-resolve"
export default {
input: "src/generators.js",
output: [
{
file: "dist/generators.js",
format: "esm",
name: "budibaseStandardComponents",
sourcemap: "inline",
},
],
plugins: [resolve()],
}

View File

@ -6,12 +6,10 @@ const serverConfig = require("../../server/config")()
const packagesFolder = ".."
const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join(
packagesFolder,
@ -50,6 +48,7 @@ const nodeModulesDist = appName =>
"standard-components",
"dist"
)
const nodeModules = appName =>
join(appPackages, appName, "node_modules", "@budibase", "standard-components")
@ -68,7 +67,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile)
for (let app of apps) {
@ -77,16 +75,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(join(publicUnauth(app), "dist"))
await copyGenerators(join(publicUnauth(app), "dist"))
}
})()

View File

@ -1,6 +0,0 @@
export { app } from "./generators/appGenerator"
export { forms } from "./generators/formsGenerator"
export { buttons } from "./generators/buttonsGenerator"
export { headers } from "./generators/headersGenerator"
export { nav } from "./generators/navGenerator"
export { indexTables } from "./generators/indexTablesGenerator"

View File

@ -1,6 +0,0 @@
import { forms } from "./formsGenerator"
import { nav } from "./navGenerator"
export const app = params => {
return [...nav(params), ...forms(params)]
}

View File

@ -1,28 +0,0 @@
export const buttons = () => [
{
name: "common/Primary Button",
description: "a styled button",
inherits: "@budibase/standard-components/button",
props: {
padding: "5px 7px",
border: "1px solid #EEE",
color: "#5F6368",
background: "##f2f2f2",
hoverColor: "black",
hoverBackground: "#cccccc",
},
},
{
name: "common/Secondary Button",
description: "a styled button",
inherits: "@budibase/standard-components/button",
props: {
padding: "5px 7px",
border: "1px solid #EEE",
color: "#5F6368",
background: "##f2f2f2",
hoverColor: "black",
hoverBackground: "#cccccc",
},
},
]

View File

@ -1,82 +0,0 @@
import { headers } from "./headersGenerator"
export const forms = ({ records, indexes }) => [
...headers({ records, indexes }),
...records.map(root),
]
const root = record => ({
name: `${record.name} Form`,
description: `All fields on record '${record.nodeKey()}' `,
inherits: "@budibase/standard-components/stackpanel",
props: {
direction: "vertical",
children: [
{
control: {
_component: "common/H1",
value: `Edit ${record.name}`,
},
},
form(record),
saveCancelButtons(record),
],
},
})
const form = record => ({
control: {
_component: "@budibase/standard-components/form",
formControls: record.fields.map(f => ({
label: f.label,
control: {
_component: "@budibase/standard-components/textbox",
value: {
"##bbstate": `current${record.name}.${f.name}`,
"##bbsource": "store",
},
},
})),
},
})
const saveCancelButtons = record => ({
control: {
_component: "@budibase/standard-components/stackpanel",
direction: "horizontal",
children: [
paddedPanelForButton({
_component: "common/Primary Button",
contentText: `Save ${record.name}`,
onClick: [
{
"##eventHandlerType": "Save Record",
parameters: {
statePath: `current${record.name}`,
},
},
],
}),
paddedPanelForButton({
_component: "common/Secondary Button",
contentText: `Cancel`,
onClick: [
{
"##eventHandlerType": "Save Record",
parameters: {
statePath: `current${record.name}`,
},
},
],
}),
],
},
})
const paddedPanelForButton = button => ({
control: {
_component: "@budibase/standard-components/panel",
padding: "20px",
component: button,
},
})

View File

@ -1,34 +0,0 @@
export const headers = () => [
{
name: "common/H1",
description: "Header 1",
inherits: "@budibase/standard-components/text",
props: {
font: "20pt",
},
},
{
name: "common/H2",
description: "Header 2",
inherits: "@budibase/standard-components/text",
props: {
font: "15pt",
},
},
{
name: "common/H3",
description: "Header 3",
inherits: "@budibase/standard-components/text",
props: {
font: "12pt bold",
},
},
{
name: "common/H4",
description: "Header 4",
inherits: "@budibase/standard-components/text",
props: {
font: "10pt bold",
},
},
]

View File

@ -1,26 +0,0 @@
export const indexTables = ({ indexes, helpers }) =>
indexes
.filter(i => i.parent().type === "root")
.map(i => indexTable(i, helpers))
export const indexTableProps = (index, helpers) => ({
data: {
"##bbstate": index.nodeKey(),
"##bbsource": "store",
},
columns: helpers.indexSchema(index).map(column),
})
const indexTable = (index, helpers) => ({
name: `tables/${index.name} Table`,
inherits: "@budibase/standard-components/table",
props: indexTableProps(index, helpers),
})
const column = col => ({
title: col.name,
value: {
"##bbstate": col.name,
"##bbsource": "context",
},
})

View File

@ -1,24 +0,0 @@
import { indexTables } from "./indexTablesGenerator"
export const nav = ({ records, indexes, helpers }) => [
{
name: "Application Root",
inherits: "@budibase/standard-components/nav",
props: {
items: indexes.filter(i => i.parent().type === "root").map(navItem),
selectedItem: {
"##bbstate": "selectedNav",
"##bbstatefallback": records[0].collectionName,
"##bbsource": "store",
},
},
},
...indexTables({ records, indexes, helpers }),
]
export const navItem = index => ({
title: index.name,
component: {
_component: `tables/${index.name} Table`,
},
})