removed generators, added simple presets to standard components

This commit is contained in:
Martin McKeaveney 2020-02-18 15:41:44 +00:00
parent 57e7a3a768
commit 3a406bc0da
45 changed files with 234 additions and 1081 deletions

View File

@ -1,24 +1,5 @@
{ {
"_lib": "./dist/index.js", "_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" : { "form" : {
"importPath": "Form", "importPath": "Form",
"name": "Form", "name": "Form",

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 packagesFolder = ".."
const jsFile = dir => join(dir, "index.js") const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map") const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist") const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist") const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json" const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join(packagesFolder, "server", "appPackages") const appPackages = join(packagesFolder, "server", "appPackages")
@ -69,7 +67,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs) const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap) const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile) const copyComponentsJson = copySource(componentsFile)
for (let app of apps) { for (let app of apps) {
@ -77,16 +74,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app)) await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app)) await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app)) await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist")) await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist")) await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist")) await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(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( const apiProxy = proxy(
[ [
"/_builder/api/**", "/_builder/api/**",
"/_builder/**/componentlibrary", "/_builder/**/componentlibrary"
"/_builder/**/componentlibraryGenerators",
], ],
{ {
target, target,

View File

@ -1,5 +1,3 @@
import { map } from "lodash/fp"
export const loadLibs = async (appName, appPackage) => { export const loadLibs = async (appName, appPackage) => {
const allLibraries = {} const allLibraries = {}
for (let lib of appPackage.pages.componentLibraries) { for (let lib of appPackage.pages.componentLibraries) {
@ -10,16 +8,6 @@ export const loadLibs = async (appName, appPackage) => {
return allLibraries 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) => { export const loadLibUrls = (appName, appPackage) => {
const allLibraries = [] const allLibraries = []
for (let lib of appPackage.pages.componentLibraries) { for (let lib of appPackage.pages.componentLibraries) {
@ -35,13 +23,5 @@ export const loadLib = async (appName, lib, allLibs) => {
return allLibs return allLibs
} }
export const loadGeneratorLib = async (appName, lib, allGeneratorLibs) => {
allGeneratorLibs[lib] = await import(makeGeneratorLibraryUrl(appName, lib))
return allGeneratorLibs
}
export const makeLibraryUrl = (appName, lib) => export const makeLibraryUrl = (appName, lib) =>
`/_builder/${appName}/componentlibrary?lib=${encodeURI(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 { expandComponentDefinition } from "../userInterface/pagesParsing/types"
import { import {
loadLibs, loadLibs,
loadLibUrls, loadLibUrls
loadGeneratorLibs,
} from "./loadComponentLibraries" } from "./loadComponentLibraries"
import { buildCodeForScreens } from "./buildCodeForScreens" import { buildCodeForScreens } from "./buildCodeForScreens"
import { generate_screen_css } from "./generate_css" import { generate_screen_css } from "./generate_css"
import { insertCodeMetadata } from "./insertCodeMetadata"
// import { uuid } from "./uuid"
let appname = "" let appname = ""
@ -94,7 +91,6 @@ export const getStore = () => {
store.deleteLevel = deleteLevel(store) store.deleteLevel = deleteLevel(store)
store.setActiveNav = setActiveNav(store) store.setActiveNav = setActiveNav(store)
store.saveScreen = saveScreen(store) store.saveScreen = saveScreen(store)
store.refreshComponents = refreshComponents(store)
store.addComponentLibrary = addComponentLibrary(store) store.addComponentLibrary = addComponentLibrary(store)
store.renameScreen = renameScreen(store) store.renameScreen = renameScreen(store)
store.deleteScreen = deleteScreen(store) store.deleteScreen = deleteScreen(store)
@ -159,8 +155,6 @@ const initialise = (store, initial) => async () => {
} }
initial.libraries = await loadLibs(appname, pkg) initial.libraries = await loadLibs(appname, pkg)
initial.generatorLibraries = await loadGeneratorLibs(appname, pkg)
initial.loadLibraryUrls = () => loadLibUrls(appname, pkg) initial.loadLibraryUrls = () => loadLibUrls(appname, pkg)
initial.appname = appname initial.appname = appname
initial.pages = pkg.pages initial.pages = pkg.pages
@ -168,7 +162,6 @@ const initialise = (store, initial) => async () => {
initial.hierarchy = pkg.appDefinition.hierarchy initial.hierarchy = pkg.appDefinition.hierarchy
initial.accessLevels = pkg.accessLevels initial.accessLevels = pkg.accessLevels
initial.screens = values(pkg.screens) initial.screens = values(pkg.screens)
initial.generators = generatorsArray(pkg.components.generators)
initial.components = values(pkg.components.components).map( initial.components = values(pkg.components.components).map(
expandComponentDefinition expandComponentDefinition
) )
@ -187,9 +180,6 @@ const initialise = (store, initial) => async () => {
return initial return initial
} }
const generatorsArray = generators =>
pipe(generators, [keys, filter(k => k !== "_lib"), map(k => generators[k])])
const showSettings = store => () => { const showSettings = store => () => {
store.update(s => { store.update(s => {
s.showSettings = !s.showSettings 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 _savePage = async s => {
const page = s.pages[s.currentPageName] const page = s.pages[s.currentPageName]
@ -749,19 +718,25 @@ const setCurrentPage = store => pageName => {
const getContainerComponent = components => const getContainerComponent = components =>
components.find(c => c.name === "@budibase/standard-components/container") components.find(c => c.name === "@budibase/standard-components/container")
const addChildComponent = store => componentName => { /**
store.update(s => { * @param {string} componentToAdd - name of the component to add to the application
const component = componentName.startsWith("##") * @param {string} presetName - name of the component preset if defined
? getBuiltin(componentName) */
: s.components.find(c => c.name === componentName) const addChildComponent = store => (componentToAdd, presetName) => {
const newComponent = createProps(component) 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 newComponent.props
) )
_savePage(s) _savePage(state)
return s
return state
}) })
} }

View File

@ -1,4 +1,8 @@
<button on:click>+</button> <button on:click>
<slot>
+
</slot>
</button>
<style> <style>
button { button {
@ -9,7 +13,6 @@
background: rgba(249, 249, 249, 1); background: rgba(249, 249, 249, 1);
width: 1.8rem; width: 1.8rem;
height: 1.8rem;
padding-bottom: 10px; padding-bottom: 10px;
display: flex; display: flex;

View File

@ -3,25 +3,27 @@
import { store } from "../builderStore" import { store } from "../builderStore"
import { find, sortBy } from "lodash/fp" import { find, sortBy } from "lodash/fp"
import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/" import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/"
import Select from "../common/Select.svelte"
import PlusButton from "../common/PlusButton.svelte"
let componentLibraries = [] let componentLibraries = []
let current_view = "text" let current_view = "text"
let selectedComponent = null
const addRootComponent = (c, all) => { const addRootComponent = (component, allComponents) => {
const { libName } = splitName(c.name) const { libName } = splitName(component.name)
let group = find(r => r.libName === libName)(all) let group = find(r => r.libName === libName)(allComponents)
if (!group) { if (!group) {
group = { group = {
libName, libName,
components: [], components: [],
generators: [],
} }
all.push(group) allComponents.push(group)
} }
group.components.push(c) group.components.push(component)
} }
const onComponentChosen = store.addChildComponent const onComponentChosen = store.addChildComponent
@ -38,9 +40,14 @@
</script> </script>
<div class="root"> <div class="root">
{#each componentLibraries as lib} <Select>
<div class="library-header">{lib.libName}</div> {#each componentLibraries as componentLibrary}
<option value={componentLibrary.libName}>
{componentLibrary.libName}
</option>
{/each}
</Select>
{#each componentLibraries as componentLibrary}
<div class="library-container"> <div class="library-container">
<ul> <ul>
<li> <li>
@ -66,11 +73,34 @@
</li> </li>
</ul> </ul>
{#each $store.builtins.concat(lib.components.filter(_ => true)) as component} {#each $store.builtins.concat(componentLibrary.components) as component}
<div <div class="component-container">
class="component" <div
on:click={() => onComponentChosen(component.name)}> class="component"
<div class="name">{splitName(component.name).componentName}</div> 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}
<PlusButton
on:click={() => {
selectedComponent = selectedComponent ? null : component.name;
}}
>
<span class="open-presets" class:open={selectedComponent === component.name}>
...
</span>
</PlusButton>
{/if}
</div> </div>
{/each} {/each}
@ -85,26 +115,22 @@
flex-direction: column; 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 { .library-container {
padding: 0 0 10px 10px; padding: 0 0 10px 10px;
flex: 1 1 auto; flex: 1 1 auto;
min-height: 0px; min-height: 0px;
} }
.component-container {
display: flex;
align-items: center;
}
.component { .component {
position: relative;
padding: 0 15px; padding: 0 15px;
cursor: pointer; cursor: pointer;
border: 1px solid #ccc; border: 1px solid #ebebeb;
border-radius: 2px; border-radius: 2px;
margin: 10px 0; margin: 10px 0;
height: 40px; height: 40px;
@ -112,6 +138,8 @@
color: #163057; color: #163057;
display: flex; display: flex;
align-items: center; align-items: center;
flex: 1;
margin-right: 5px;
} }
.component:hover { .component:hover {
@ -132,12 +160,38 @@
padding: 0; 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 { li {
margin-right: 20px; margin-right: 20px;
background: none; background: none;
border-radius: 5px; border-radius: 5px;
width: 48px;
height: 48px;
} }
li button { li button {

View File

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

View File

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

View File

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

View File

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

View File

@ -573,23 +573,6 @@
lodash "^4.17.10" lodash "^4.17.10"
to-fast-properties "^2.0.0" 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@*": "@types/body-parser@*":
version "1.17.0" version "1.17.0"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c" 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" version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 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: debug@=3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@ -1438,11 +1416,6 @@ loose-envify@^1.0.0:
dependencies: dependencies:
js-tokens "^3.0.0 || ^4.0.0" 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: make-dir@^1.0.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" 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" version "2.11.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766" 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: nanomatch@^1.2.9:
version "1.2.13" version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" 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" is-plain-object "^2.0.3"
split-string "^3.0.1" 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: signal-exit@^3.0.0:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"

View File

@ -1,6 +1,5 @@
{ {
"_lib": "./dist/index.js", "_lib": "./dist/index.js",
"_generators": {},
"Body1": { "Body1": {
"name": "Body1", "name": "Body1",
"description": "Sets the font properties as Roboto Body 1", "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 packagesFolder = ".."
const jsFile = dir => join(dir, "index.js") const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map") const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist") const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist") const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json" const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join( const appPackages = join(
packagesFolder, packagesFolder,
@ -68,7 +66,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs) const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap) const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile) const copyComponentsJson = copySource(componentsFile)
for (let app of apps) { for (let app of apps) {
@ -77,16 +74,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app)) await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app)) await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app)) await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist")) await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist")) await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist")) await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(join(publicUnauth(app), "dist")) await copySourceJsMap(join(publicUnauth(app), "dist"))
await copyGenerators(join(publicUnauth(app), "dist"))
} }
})() })()

View File

@ -0,0 +1,11 @@
export const TEXTFIELD = {
STANDARD: {
variant: "standard"
},
FILLED: {
variant: "filled"
},
OUTLINED: {
variant: "outlined"
}
};

View File

@ -6,12 +6,10 @@ const serverConfig = require("../../../server/config")()
const packagesFolder = ".." const packagesFolder = ".."
const jsFile = dir => join(dir, "index.js") const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map") const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist") const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist") const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json" const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join( const appPackages = join(
packagesFolder, packagesFolder,
@ -68,7 +66,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs) const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap) const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile) const copyComponentsJson = copySource(componentsFile)
for (let app of apps) { for (let app of apps) {
@ -77,16 +74,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app)) await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app)) await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app)) await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist")) await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist")) await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist")) await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(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 send = require("koa-send")
const { const {
getPackageForBuilder, getPackageForBuilder,
getComponents, getComponentDefinitions,
getApps, getApps,
saveScreen, saveScreen,
renameScreen, renameScreen,
@ -70,16 +70,6 @@ module.exports = (config, app) => {
) )
await send(ctx, info.components._lib || "index.js", { root: info.libDir }) 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) => { .get("/_builder/*", async (ctx, next) => {
if (!config.dev) { if (!config.dev) {
ctx.response.status = StatusCodes.FORBIDDEN ctx.response.status = StatusCodes.FORBIDDEN
@ -151,7 +141,7 @@ module.exports = (config, app) => {
}) })
.get("/_builder/api/:appname/components", async ctx => { .get("/_builder/api/:appname/components", async ctx => {
try { 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 ctx.response.status = StatusCodes.OK
} catch (e) { } catch (e) {
if (e.status) { if (e.status) {
@ -171,15 +161,6 @@ module.exports = (config, app) => {
ctx.body = info.components ctx.body = info.components
ctx.response.status = StatusCodes.OK 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 => { .post("/_builder/api/:appname/backend", async ctx => {
await saveBackend( await saveBackend(
config, config,

View File

@ -1,6 +1,11 @@
const { readJSON, exists } = require("fs-extra") const { readJSON, exists } = require("fs-extra")
const { resolve, join, dirname } = require("path") 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) => { const getLibDir = (appPath, libname) => {
try { try {
const componentsFile = require.resolve(join(libname, "components.json"), { const componentsFile = require.resolve(join(libname, "components.json"), {
@ -17,11 +22,18 @@ const getComponentsFilepath = libPath => resolve(libPath, "components.json")
module.exports.componentsFilepath = (appPath, libname) => module.exports.componentsFilepath = (appPath, libname) =>
getComponentsFilepath(getLibDir(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) => { module.exports.componentLibraryInfo = async (appPath, libname) => {
const libDir = getLibDir(appPath, libname) const libDir = getLibDir(appPath, libname)
const componentsPath = getComponentsFilepath(libDir) const componentsPath = getComponentsFilepath(libDir)
if (!(await exists(componentsPath))) { const componentDefinitionExists = await exists(componentsPath);
if (!componentDefinitionExists) {
const e = new Error( const e = new Error(
`could not find components definition file at ${componentsPath}` `could not find components definition file at ${componentsPath}`
) )
@ -30,29 +42,17 @@ module.exports.componentLibraryInfo = async (appPath, libname) => {
} }
try { try {
const components = await readJSON(componentsPath) const componentDefinitions = await readJSON(componentsPath)
const namespacedComponents = { _lib: components._lib } const namespacedComponents = { _lib: componentDefinitions._lib }
for (let cname in components) { for (let componentKey in componentDefinitions) {
if (cname === "_lib" || cname == "_generators") continue if (componentKey === "_lib") continue
const namespacedName = `${libname}/${cname}` const namespacedName = `${libname}/${componentKey}`
components[cname].name = namespacedName componentDefinitions[componentKey].name = namespacedName
namespacedComponents[namespacedName] = components[cname] namespacedComponents[namespacedName] = componentDefinitions[componentKey]
}
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]
}
} }
return { return {
components: namespacedComponents, components: namespacedComponents,
generators: namespacedGenerators,
libDir, libDir,
componentsPath, componentsPath,
} }

View File

@ -39,7 +39,7 @@ module.exports.getPackageForBuilder = async (config, appname) => {
pages, 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) 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) const appPath = appPackageFolder(config, appname)
return await componentLibraryInfo(appPath, lib) return await componentLibraryInfo(appPath, componentLibrary)
} }
const getComponents = async (appPath, pages, lib) => { /**
let libs * @param {string} appPath - path to a budibase application
if (!lib) { * @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)) pages = pages || (await getPages(appPath))
if (!pages) return [] if (!pages) return []
libs = $(pages, [values, map(p => p.componentLibraries), flatten]) componentLibraries = $(pages, [values, map(p => p.componentLibraries), flatten])
} else { } else {
libs = [lib] componentLibraries = [componentLibrary]
} }
const components = {} const components = {}
const generators = {}
for (let l of libs) { for (let library of componentLibraries) {
const info = await componentLibraryInfo(appPath, l) const info = await componentLibraryInfo(appPath, library)
merge(components, info.components) merge(components, info.components)
merge(generators, info.generators)
} }
if (components._lib) delete components._lib 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" lodash "^4.17.13"
to-fast-properties "^2.0.0" 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": "@cnakazawa/watch@^1.0.3":
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
@ -322,11 +299,6 @@
path-to-regexp "^1.1.1" path-to-regexp "^1.1.1"
urijs "^1.19.0" 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": "@types/babel__core@^7.1.0":
version "7.1.2" version "7.1.2"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f" 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-mimetype "^2.2.0"
whatwg-url "^7.0.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: debug@^2.2.0, debug@^2.3.3:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 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" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= 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" version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@ -2810,11 +2777,6 @@ lru-cache@^4.0.1:
pseudomap "^1.0.2" pseudomap "^1.0.2"
yallist "^2.1.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: make-dir@^1.0.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" 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" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== 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: nanomatch@^1.2.9:
version "1.2.13" version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" 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" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== 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: signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@ -4100,11 +4050,6 @@ supports-color@^6.1.0:
dependencies: dependencies:
has-flag "^3.0.0" 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: symbol-tree@^3.2.2:
version "3.2.4" version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"

View File

@ -1,32 +1,5 @@
{ {
"_lib": "./dist/index.js", "_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" : { "button" : {
"name": "Button", "name": "Button",
"description": "an html <button />", "description": "an html <button />",
@ -43,7 +16,28 @@
"hoverBackground": "string", "hoverBackground": "string",
"hoverBorder": "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" : { "login" : {
"name": "Login Control", "name": "Login Control",

View File

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

View File

@ -27513,7 +27513,7 @@ var app = (function (crypto$1) {
var main = "dist/index.js"; var main = "dist/index.js";
var module = "dist/index.js"; var module = "dist/index.js";
var scripts = { var scripts = {
build: "rollup -c && rollup -c rollup.generatorsconfig.js", build: "rollup -c",
prepublishOnly: "npm run build", prepublishOnly: "npm run build",
testbuild: "rollup -w -c rollup.testconfig.js", testbuild: "rollup -w -c rollup.testconfig.js",
dev: "run-p start:dev testbuild", 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 packagesFolder = ".."
const jsFile = dir => join(dir, "index.js") const jsFile = dir => join(dir, "index.js")
const generatorsFile = dir => join(dir, "generators.js")
const jsMapFile = dir => join(dir, "index.js.map") const jsMapFile = dir => join(dir, "index.js.map")
const sourceJs = jsFile("dist") const sourceJs = jsFile("dist")
const sourceJsMap = jsMapFile("dist") const sourceJsMap = jsMapFile("dist")
const componentsFile = "components.json" const componentsFile = "components.json"
const sourceGenerators = generatorsFile("dist")
const appPackages = join( const appPackages = join(
packagesFolder, packagesFolder,
@ -50,6 +48,7 @@ const nodeModulesDist = appName =>
"standard-components", "standard-components",
"dist" "dist"
) )
const nodeModules = appName => const nodeModules = appName =>
join(appPackages, appName, "node_modules", "@budibase", "standard-components") join(appPackages, appName, "node_modules", "@budibase", "standard-components")
@ -68,7 +67,6 @@ const nodeModules = appName =>
const copySourceJs = copySource(sourceJs) const copySourceJs = copySource(sourceJs)
const copySourceJsMap = copySource(sourceJsMap) const copySourceJsMap = copySource(sourceJsMap)
const copyGenerators = copySource(sourceGenerators)
const copyComponentsJson = copySource(componentsFile) const copyComponentsJson = copySource(componentsFile)
for (let app of apps) { for (let app of apps) {
@ -77,16 +75,13 @@ const nodeModules = appName =>
await copySourceJs(nodeModulesDist(app)) await copySourceJs(nodeModulesDist(app))
await copySourceJsMap(nodeModulesDist(app)) await copySourceJsMap(nodeModulesDist(app))
await copyGenerators(nodeModulesDist(app))
await copyComponentsJson(nodeModules(app)) await copyComponentsJson(nodeModules(app))
await copySourceJs(join(publicMain(app), "dist")) await copySourceJs(join(publicMain(app), "dist"))
await copySourceJsMap(join(publicMain(app), "dist")) await copySourceJsMap(join(publicMain(app), "dist"))
await copyGenerators(join(publicMain(app), "dist"))
await copySourceJs(join(publicUnauth(app), "dist")) await copySourceJs(join(publicUnauth(app), "dist"))
await copySourceJsMap(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`,
},
})