data components
This commit is contained in:
parent
96a1bc52de
commit
db69673a9d
|
@ -46,10 +46,4 @@
|
|||
background: #fafafa;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
select {
|
||||
width: 100%;
|
||||
}
|
||||
option {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import PropsView from "./PropsView.svelte"
|
||||
import StateBindingControl from "./StateBindingControl.svelte"
|
||||
import { store } from "builderStore"
|
||||
import IconButton from "components/common/IconButton.svelte"
|
||||
import {
|
||||
|
@ -30,7 +29,6 @@
|
|||
? getProps($store.currentPreviewItem, ["name", "favicon"])
|
||||
: getProps($store.currentPreviewItem, ["name", "description", "route"])
|
||||
|
||||
const onPropChanged = store.setComponentProp
|
||||
const onStyleChanged = store.setComponentStyle
|
||||
|
||||
function getProps(obj, keys) {
|
||||
|
@ -89,14 +87,14 @@
|
|||
on:input={({ target }) => store.setMetadataProp(k, target.value)} />
|
||||
</div>
|
||||
{/each}
|
||||
<PropsView {component} {components} {onPropChanged} />
|
||||
<PropsView {component} {components} />
|
||||
{:else}
|
||||
<PropsView {component} {components} {onPropChanged} />
|
||||
<PropsView {component} {components} />
|
||||
{/if}
|
||||
{:else if current_view === 'layout'}
|
||||
<LayoutEditor {onStyleChanged} {component} />
|
||||
{:else if current_view === 'events'}
|
||||
<EventsEditor {component} {components} {onPropChanged} />
|
||||
<EventsEditor {component} {components} />
|
||||
{/if}
|
||||
|
||||
<CodeEditor
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { store } from "builderStore";
|
||||
import Modal from "../../common/Modal.svelte"
|
||||
import HandlerSelector from "./HandlerSelector.svelte"
|
||||
import IconButton from "../../common/IconButton.svelte"
|
||||
|
@ -14,7 +15,6 @@
|
|||
export let eventOptions = []
|
||||
export let open
|
||||
export let onClose
|
||||
export let onPropChanged
|
||||
|
||||
let eventType = ""
|
||||
let draftEventHandler = { parameters: [] }
|
||||
|
@ -52,12 +52,12 @@
|
|||
}
|
||||
|
||||
const deleteEvent = () => {
|
||||
onPropChanged(eventType, [])
|
||||
store.setComponentProp(eventType, [])
|
||||
closeModal()
|
||||
}
|
||||
|
||||
const saveEventData = () => {
|
||||
onPropChanged(eventType, eventData.handlers)
|
||||
store.setComponentProp(eventType, eventData.handlers)
|
||||
closeModal()
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
export const EVENT_TYPE = "event"
|
||||
|
||||
export let component
|
||||
export let onPropChanged = () => {}
|
||||
export let components
|
||||
|
||||
let modalOpen = false
|
||||
|
@ -74,7 +73,6 @@
|
|||
</form>
|
||||
</div>
|
||||
<EventEditorModal
|
||||
{onPropChanged}
|
||||
open={modalOpen}
|
||||
onClose={closeModal}
|
||||
eventOptions={events}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import PlusButton from "components/common/PlusButton.svelte"
|
||||
import Select from "components/common/Select.svelte"
|
||||
import StateBindingCascader from "./StateBindingCascader.svelte"
|
||||
import StateBindingControl from "../StateBindingControl.svelte"
|
||||
import { find, map, keys, reduce, keyBy } from "lodash/fp"
|
||||
import { pipe } from "components/common/core"
|
||||
import {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import PlusButton from "components/common/PlusButton.svelte"
|
||||
import Select from "components/common/Select.svelte"
|
||||
import Input from "components/common/Input.svelte"
|
||||
import StateBindingControl from "../StateBindingControl.svelte"
|
||||
import { find, map, keys, reduce, keyBy } from "lodash/fp"
|
||||
import { pipe } from "components/common/core"
|
||||
import {
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
<script>
|
||||
import { store } from "builderStore";
|
||||
import Checkbox from "../common/Checkbox.svelte"
|
||||
import Textbox from "../common/Textbox.svelte"
|
||||
import Dropdown from "../common/Dropdown.svelte"
|
||||
import StateBindingControl from "./StateBindingControl.svelte"
|
||||
|
||||
export let setProp = () => {}
|
||||
export let index
|
||||
export let prop_name
|
||||
export let prop_value
|
||||
export let prop_definition = {}
|
||||
|
||||
const setComponentProp = props => {
|
||||
setProp(propDef.____name, props)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
@ -23,7 +19,7 @@
|
|||
type={prop_definition.type || prop_definition}
|
||||
options={prop_definition.options}
|
||||
styleBindingProperty={prop_definition.styleBindingProperty}
|
||||
onChanged={v => setProp(prop_name, v)} />
|
||||
onChanged={v => store.setComponentProp(prop_name, v)} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -6,17 +6,12 @@
|
|||
import IconButton from "../common/IconButton.svelte"
|
||||
|
||||
export let component
|
||||
export let onPropChanged = () => {}
|
||||
export let components
|
||||
|
||||
let errors = []
|
||||
const props_to_ignore = ["_component", "_children", "_styles", "_code", "_id"]
|
||||
|
||||
$: componentDef = components[component._component]
|
||||
|
||||
let setProp = (name, value) => {
|
||||
onPropChanged(name, value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
@ -27,7 +22,6 @@
|
|||
{#if prop_def !== 'event'}
|
||||
<div class="prop-container">
|
||||
<PropControl
|
||||
{setProp}
|
||||
{prop_name}
|
||||
prop_value={component[prop_name]}
|
||||
prop_definition={prop_def}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
export let styleBindingProperty = ""
|
||||
|
||||
$: bindOptionToStyle = !!styleBindingProperty
|
||||
|
||||
</script>
|
||||
|
||||
<div class="unbound-container">
|
||||
|
@ -26,10 +27,12 @@
|
|||
{:else if type === 'models'}
|
||||
<select
|
||||
class="uk-select uk-form-small"
|
||||
{value}
|
||||
on:change={ev => onChanged(ev.target.value)}>
|
||||
bind:value
|
||||
on:change={() => {
|
||||
onChanged(value)
|
||||
}}>
|
||||
{#each $backendUiStore.models || [] as option}
|
||||
<option value={`all_${option._id}`}>{option.name}</option>
|
||||
<option value={option}>{option.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else if type === 'options' || type === 'models'}
|
||||
|
|
|
@ -189,6 +189,22 @@ export default {
|
|||
commonProps: {},
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "Chart",
|
||||
_component: "@budibase/standard-components/datachart",
|
||||
description: "Shiny chart",
|
||||
icon: "ri-bar-chart-line",
|
||||
commonProps: {},
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "List",
|
||||
_component: "@budibase/standard-components/datalist",
|
||||
description: "Shiny list",
|
||||
icon: "ri-file-list-line",
|
||||
commonProps: {},
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -29,9 +29,12 @@ export const loadBudibase = async opts => {
|
|||
// let { appRootPath } = frontendDefinition;
|
||||
// appRootPath = appRootPath === "" ? "" : "/" + trimSlash(appRootPatl)
|
||||
|
||||
const componentLibraryModules = opts.componentLibraries || {}
|
||||
const componentLibraryModules = opts && opts.componentLibraries || {}
|
||||
|
||||
const libraries = frontendDefinition.libraries || []
|
||||
const libraries = frontendDefinition.libraries || [
|
||||
"@budibase/materialdesign-components",
|
||||
"@budibase/standard-components"
|
||||
]
|
||||
|
||||
for (let library of libraries) {
|
||||
// fetch the JavaScript for the component libraries from the server
|
||||
|
|
|
@ -45,7 +45,10 @@ exports.save = async function(ctx) {
|
|||
// record: record,
|
||||
// })
|
||||
|
||||
ctx.body = record
|
||||
ctx.body = {
|
||||
...record,
|
||||
...response
|
||||
}
|
||||
ctx.status = 200
|
||||
ctx.message = `${model.name} created successfully`
|
||||
}
|
||||
|
|
|
@ -276,6 +276,45 @@
|
|||
"model": "models"
|
||||
}
|
||||
},
|
||||
"datalist": {
|
||||
"description": "A configurable data list that attaches to your backend models.",
|
||||
"data": true,
|
||||
"props": {
|
||||
"model": "models",
|
||||
"layout": {
|
||||
"type": "options",
|
||||
"default": "list",
|
||||
"options": [
|
||||
"list",
|
||||
"grid"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"datachart": {
|
||||
"description": "shiny chart",
|
||||
"data": true,
|
||||
"props": {
|
||||
"model": "models",
|
||||
"type": {
|
||||
"type": "options",
|
||||
"default": "column2d",
|
||||
"options": [
|
||||
"column3d",
|
||||
"line",
|
||||
"area2d",
|
||||
"bar2d",
|
||||
"bar3d",
|
||||
"pie2d",
|
||||
"pie3d",
|
||||
"doughnut2d",
|
||||
"doughnut3d",
|
||||
"pareto2d",
|
||||
"pareto3d"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"description": "an HTML anchor <a> tag",
|
||||
"props": {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"devDependencies": {
|
||||
"@budibase/client": "^0.0.32",
|
||||
"@nx-js/compiler-util": "^2.0.0",
|
||||
"@rollup/plugin-commonjs": "^11.1.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"fs-extra": "^8.1.0",
|
||||
"lodash": "^4.17.15",
|
||||
|
@ -34,5 +35,9 @@
|
|||
],
|
||||
"version": "0.0.32",
|
||||
"license": "MIT",
|
||||
"gitHead": "b1f4f90927d9e494e513220ef060af28d2d42455"
|
||||
"gitHead": "b1f4f90927d9e494e513220ef060af28d2d42455",
|
||||
"dependencies": {
|
||||
"fusioncharts": "^3.15.1-sr.1",
|
||||
"svelte-fusioncharts": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import svelte from "rollup-plugin-svelte"
|
||||
import resolve from "rollup-plugin-node-resolve"
|
||||
import commonjs from "@rollup/plugin-commonjs"
|
||||
|
||||
export default {
|
||||
input: "src/index.js",
|
||||
|
@ -15,6 +16,9 @@ export default {
|
|||
svelte({
|
||||
hydratable: true,
|
||||
}),
|
||||
resolve(),
|
||||
resolve({
|
||||
browser: true,
|
||||
}),
|
||||
commonjs()
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,22 +1,38 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { onMount } from "svelte";
|
||||
import FusionCharts from "fusioncharts";
|
||||
import Charts from "fusioncharts/fusioncharts.charts";
|
||||
import FusionTheme from "fusioncharts/themes/fusioncharts.theme.fusion";
|
||||
import SvelteFC, {fcRoot} from 'svelte-fusioncharts';
|
||||
|
||||
fcRoot(FusionCharts, Charts, FusionTheme);
|
||||
|
||||
export let _bb
|
||||
export let onLoad
|
||||
export let _instanceId
|
||||
export let model
|
||||
export let type = "column2d"
|
||||
|
||||
let cssVariables
|
||||
let headers = []
|
||||
let data = []
|
||||
let store = _bb.store
|
||||
|
||||
$: chartConfigs = {
|
||||
type,
|
||||
width: '600',
|
||||
height: '400',
|
||||
dataFormat: 'json',
|
||||
dataSource: {
|
||||
data: $store[model._id] || []
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchData() {
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/${model}/records`
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/all_${model._id}/records`
|
||||
const response = await _bb.api.get(FETCH_RECORDS_URL)
|
||||
if (response.status === 200) {
|
||||
const json = await response.json()
|
||||
|
||||
data = json
|
||||
store.update(state => {
|
||||
state[model._id] = json
|
||||
return state
|
||||
})
|
||||
} else {
|
||||
throw new Error("Failed to fetch records.", response)
|
||||
}
|
||||
|
@ -25,75 +41,9 @@
|
|||
onMount(async () => {
|
||||
await fetchData()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<!-- This prop was in the old one -->
|
||||
<!-- use:cssVars={cssVariables} -->
|
||||
|
||||
<table class="uk-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{#each headers as header}
|
||||
<th>{header}</th>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each data as row}
|
||||
<tr>
|
||||
{#each headers as header}
|
||||
{#if row[header]}
|
||||
<td>{row[header]}</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- <button
|
||||
bind:this={theButton}
|
||||
use:cssVars={cssVariables}
|
||||
class="{className}
|
||||
{customClasses}"
|
||||
disabled={disabled || false}
|
||||
on:click={clickHandler}
|
||||
style={buttonStyles}>
|
||||
{#if !_bb.props._children || _bb.props._children.length === 0}
|
||||
{contentText}
|
||||
{/if}
|
||||
</button> -->
|
||||
|
||||
<style>
|
||||
table {
|
||||
border: 1px solid #ccc;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
thead {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
thead th {
|
||||
color: var(--button-text);
|
||||
text-transform: capitalize;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
text-rendering: optimizeLegibility;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
border-bottom: 1px solid #ccc;
|
||||
transition: 0.3s background-color;
|
||||
color: var(--secondary100);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
<div id="container">
|
||||
<SvelteFC {...chartConfigs} />
|
||||
</div>
|
|
@ -2,26 +2,73 @@
|
|||
import { onMount } from "svelte"
|
||||
|
||||
export let _bb
|
||||
export let _viewName
|
||||
export let _instanceId
|
||||
export let model
|
||||
|
||||
let username
|
||||
let password
|
||||
let newModel = {
|
||||
modelId: model._id
|
||||
}
|
||||
let store = _bb.store
|
||||
|
||||
$: fields = Object.keys(model.schema)
|
||||
|
||||
async function save() {
|
||||
const SAVE_RECORD_URL = `/api/${_instanceId}/records`
|
||||
const response = await _bb.api.post(SAVE_RECORD_URL, newModel);
|
||||
const json = await response.json();
|
||||
|
||||
store.update(state => {
|
||||
state[model._id] = [
|
||||
...state[model._id],
|
||||
json
|
||||
]
|
||||
return state
|
||||
});
|
||||
}
|
||||
|
||||
const handleInput = field => event => {
|
||||
let value
|
||||
|
||||
if (event.target.type === "checkbox") {
|
||||
value = event.target.checked
|
||||
newModel[field] = value
|
||||
return
|
||||
}
|
||||
|
||||
if (event.target.type === "number") {
|
||||
value = parseInt(event.target.value)
|
||||
newModel[field] = value
|
||||
return
|
||||
}
|
||||
|
||||
value = event.target.value
|
||||
newModel[field] = value
|
||||
}
|
||||
</script>
|
||||
|
||||
<form class="uk-form">
|
||||
<form class="uk-form" on:submit|preventDefault>
|
||||
<h4>{model.name}</h4>
|
||||
<div>
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="form-stacked-text">Username</label>
|
||||
<input class="uk-input" type="text" bind:value={username} />
|
||||
</div>
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="form-stacked-text">Password</label>
|
||||
<input class="uk-input" type="password" bind:value={password} />
|
||||
</div>
|
||||
{#each fields as field}
|
||||
<div class="uk-margin">
|
||||
<label class="form-label" for="form-stacked-text">{field}</label>
|
||||
<input
|
||||
class="uk-input"
|
||||
type={model.schema[field].type === "string" ? "text" : model.schema[field].type}
|
||||
on:change={handleInput(field)}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<button on:click={save}>
|
||||
SAVE
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
|
||||
.form-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
|
||||
export let _bb
|
||||
export let _instanceId
|
||||
export let model
|
||||
export let layout = "list"
|
||||
|
||||
let headers = []
|
||||
let store = _bb.store
|
||||
|
||||
async function fetchData() {
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/all_${model._id}/records`
|
||||
const response = await _bb.api.get(FETCH_RECORDS_URL)
|
||||
if (response.status === 200) {
|
||||
const json = await response.json()
|
||||
|
||||
store.update(state => {
|
||||
state[model._id] = json
|
||||
return state
|
||||
});
|
||||
} else {
|
||||
throw new Error("Failed to fetch records.", response)
|
||||
}
|
||||
}
|
||||
|
||||
$: data = $store[model._id] || []
|
||||
|
||||
onMount(async () => {
|
||||
await fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<section
|
||||
class:grid={layout === "grid"}
|
||||
class:list={layout === "list"}
|
||||
>
|
||||
{#each data as data}
|
||||
<div class="data-card">
|
||||
<ul>
|
||||
{#each Object.keys(data) as key}
|
||||
<li>
|
||||
<span class="data-key">
|
||||
{key}:
|
||||
</span>
|
||||
<span class="data-value">
|
||||
{data[key]}
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/each}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: Roboto;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 5px 0 5px 0;
|
||||
}
|
||||
|
||||
.data-card {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.data-key {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
export let _bb
|
||||
export let model
|
||||
|
||||
let searchValue = ""
|
||||
|
||||
function search() {
|
||||
const SEARCH_URL =
|
||||
_bb.api.get(``);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<input type="text" bind:value={searchValue}>
|
||||
<button on:click={search}>Search</button>
|
||||
</div>
|
|
@ -1,38 +1,38 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
// import { cssVars, createClasses } from "./cssVars"
|
||||
// import { buildStyle } from "./buildStyle"
|
||||
|
||||
export let _bb
|
||||
export let onLoad
|
||||
export let _instanceId
|
||||
export let model
|
||||
|
||||
let cssVariables
|
||||
let headers = []
|
||||
let data = []
|
||||
let store = _bb.store
|
||||
|
||||
async function fetchData() {
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/${model}/records`
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/all_${model._id}/records`
|
||||
const response = await _bb.api.get(FETCH_RECORDS_URL)
|
||||
if (response.status === 200) {
|
||||
const json = await response.json()
|
||||
|
||||
data = json
|
||||
headers = Object.keys(data[0]).filter(key => !key.startsWith("_"))
|
||||
store.update(state => {
|
||||
state[model._id] = json
|
||||
return state
|
||||
});
|
||||
|
||||
headers = Object.keys(json[0]).filter(key => !key.startsWith("_"))
|
||||
} else {
|
||||
throw new Error("Failed to fetch records.", response)
|
||||
}
|
||||
}
|
||||
|
||||
$: data = $store[model._id] || []
|
||||
|
||||
onMount(async () => {
|
||||
await fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- This prop was in the old one -->
|
||||
<!-- use:cssVars={cssVariables} -->
|
||||
|
||||
<table class="uk-table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -54,19 +54,6 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- <button
|
||||
bind:this={theButton}
|
||||
use:cssVars={cssVariables}
|
||||
class="{className}
|
||||
{customClasses}"
|
||||
disabled={disabled || false}
|
||||
on:click={clickHandler}
|
||||
style={buttonStyles}>
|
||||
{#if !_bb.props._children || _bb.props._children.length === 0}
|
||||
{contentText}
|
||||
{/if}
|
||||
</button> -->
|
||||
|
||||
<style>
|
||||
table {
|
||||
border: 1px solid #ccc;
|
||||
|
|
|
@ -16,3 +16,6 @@ export { default as icon } from "./Icon.svelte"
|
|||
export { default as Navigation } from "./Navigation.svelte"
|
||||
export { default as datatable } from "./DataTable.svelte"
|
||||
export { default as dataform } from "./DataForm.svelte"
|
||||
export { default as datachart } from "./DataChart.svelte"
|
||||
export { default as datalist } from "./DataList.svelte"
|
||||
export { default as datasearch } from "./DataSearch.svelte"
|
||||
|
|
Loading…
Reference in New Issue