Browse Source

moving code from main store to backend file

master
Martin McKeaveney 7 years ago
parent
commit
fa95ba2d79
  1. 163
      packages/builder/src/builderStore/store/backend.js
  2. 229
      packages/builder/src/builderStore/store/index.js
  3. 15
      packages/builder/src/database/ActionsHeader.svelte
  4. 71
      packages/builder/src/database/DatabaseRoot.svelte
  5. 5
      packages/builder/src/database/IndexView.svelte
  6. 62
      packages/builder/src/database/ModelDataTable/ModelDataTable.svelte
  7. 26
      packages/builder/src/database/ModelDataTable/api.js
  8. 2
      packages/builder/src/database/ModelDataTable/modals/CreateEditModel.svelte
  9. 108
      packages/builder/src/database/ModelDataTable/modals/CreateEditRecord.svelte
  10. 10
      packages/builder/src/database/ModelDataTable/modals/DeleteRecord.svelte
  11. 5
      packages/builder/src/database/ModelView.svelte
  12. 2
      packages/builder/src/nav/DatabasesList.svelte
  13. 6
      packages/builder/src/nav/SchemaManagementDrawer.svelte
  14. 0
      packages/client/src/state/stateManager/dynamicPropertySource.js
  15. 5
      packages/core/src/recordApi/getNew.js

163
packages/builder/src/builderStore/store/backend.js

@ -0,0 +1,163 @@
import api from "../api"
import {
filter,
cloneDeep,
sortBy,
find
} from "lodash/fp"
import { hierarchy as hierarchyFunctions } from "../../../../core/src"
import {
pipe,
getNode,
validate,
constructHierarchy,
templateApi,
} from "../../common/core"
import { store } from "../index";
export const createShadowHierarchy = hierarchy =>
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))
export const saveBackend = async state => {
await api.post(`/_builder/api/${state.appname}/backend`, {
appDefinition: {
hierarchy: state.hierarchy,
actions: state.actions,
triggers: state.triggers,
},
accessLevels: state.accessLevels,
})
}
export const newRecord = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
const parent = useRoot
? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId)
s.errors = []
s.currentNode = templateApi(shadowHierarchy).getNewRecordTemplate(
parent,
"",
true
)
return s
})
}
export const selectExistingNode = store => nodeId => {
store.update(s => {
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
s.currentNode = getNode(shadowHierarchy, nodeId)
s.currentNodeIsNew = false
s.errors = []
return s
})
}
export const newIndex = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true
s.errors = []
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
const parent = useRoot
? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId)
s.currentNode = templateApi(shadowHierarchy).getNewIndexTemplate(parent)
return s
})
}
// TODO: ONLY SEEMS TO BE CALLED BY THE BACKEND
export const saveCurrentNode = store => () => {
store.update(s => {
const errors = validate.node(s.currentNode)
s.errors = errors
if (errors.length > 0) {
return s
}
const parentNode = getNode(s.hierarchy, s.currentNode.parent().nodeId)
const existingNode = getNode(s.hierarchy, s.currentNode.nodeId)
let index = parentNode.children.length
if (existingNode) {
// remove existing
index = existingNode.parent().children.indexOf(existingNode)
existingNode.parent().children = pipe(existingNode.parent().children, [
filter(c => c.nodeId !== existingNode.nodeId),
])
}
// should add node into existing hierarchy
const cloned = cloneDeep(s.currentNode)
templateApi(s.hierarchy).constructNode(parentNode, cloned)
const newIndexOfChild = child => {
if (child === cloned) return index
const currentIndex = parentNode.children.indexOf(child)
return currentIndex >= index ? currentIndex + 1 : currentIndex
}
parentNode.children = pipe(parentNode.children, [sortBy(newIndexOfChild)])
if (!existingNode && s.currentNode.type === "record") {
const defaultIndex = templateApi(s.hierarchy).getNewIndexTemplate(
cloned.parent()
)
defaultIndex.name = `all_${cloned.collectionName}`
defaultIndex.allowedRecordNodeIds = [cloned.nodeId]
}
s.currentNodeIsNew = false
saveBackend(s)
return s
})
}
export const deleteCurrentNode = store => () => {
store.update(s => {
const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId)
s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
? find(n => n != s.currentNode)(s.hierarchy.children)
: nodeToDelete.parent()
if (hierarchyFunctions.isRecord(nodeToDelete)) {
nodeToDelete.parent().children = filter(
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().children)
} else {
nodeToDelete.parent().indexes = filter(
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().indexes)
}
s.errors = []
saveBackend(s)
return s
})
}
export const saveField = databaseStore => field => {
databaseStore.update(db => {
db.currentNode.fields = filter(f => f.name !== field.name)(
db.currentNode.fields
)
templateApi(db.hierarchy).addField(db.currentNode, field)
return db
})
}
export const deleteField = databaseStore => field => {
databaseStore.update(db => {
db.currentNode.fields = filter(f => f.name !== field.name)(
db.currentNode.fields
)
return db
})
}

229
packages/builder/src/builderStore/store.js → packages/builder/src/builderStore/store/index.js

@ -1,8 +1,7 @@
import { hierarchy as hierarchyFunctions } from "../../../core/src"
import { import {
filter, filter,
cloneDeep, cloneDeep,
sortBy, // sortBy,
map, map,
last, last,
concat, concat,
@ -13,27 +12,28 @@ import {
import { import {
pipe, pipe,
getNode, getNode,
validate, // validate,
constructHierarchy, constructHierarchy,
templateApi, // templateApi,
} from "../common/core" } from "../../common/core"
import * as backendStoreActions from "./backend";
import { writable } from "svelte/store" import { writable } from "svelte/store"
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject" import { defaultPagesObject } from "../../userInterface/pagesParsing/defaultPagesObject"
import api from "./api" import api from "../api"
import { getExactComponent } from "../userInterface/pagesParsing/searchComponents" import { getExactComponent } from "../../userInterface/pagesParsing/searchComponents"
import { rename } from "../userInterface/pagesParsing/renameScreen" import { rename } from "../../userInterface/pagesParsing/renameScreen"
import { import {
getNewScreen, getNewScreen,
createProps, createProps,
makePropsSafe, makePropsSafe,
getBuiltin, getBuiltin,
} from "../userInterface/pagesParsing/createProps" } from "../../userInterface/pagesParsing/createProps"
import { expandComponentDefinition } from "../userInterface/pagesParsing/types" import { expandComponentDefinition } from "../../userInterface/pagesParsing/types"
import { loadLibs, libUrlsForPreview } from "./loadComponentLibraries" import { loadLibs, libUrlsForPreview } 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 { insertCodeMetadata } from "../insertCodeMetadata"
import { uuid } from "./uuid" import { uuid } from "../uuid"
let appname = "" let appname = ""
@ -121,16 +121,18 @@ export const getStore = () => {
// } // }
store.initialise = initialise(store, initial) store.initialise = initialise(store, initial)
store.newChildRecord = newRecord(store, false)
store.newRootRecord = newRecord(store, true) store.newChildRecord = backendStoreActions.newRecord(store, false)
store.selectExistingNode = selectExistingNode(store) store.newRootRecord = backendStoreActions.newRecord(store, true)
store.newChildIndex = newIndex(store, false) store.selectExistingNode = backendStoreActions.selectExistingNode(store)
store.newRootIndex = newIndex(store, true) store.newChildIndex = backendStoreActions.newIndex(store, false)
store.saveCurrentNode = saveCurrentNode(store) store.newRootIndex = backendStoreActions.newIndex(store, true)
store.saveCurrentNode = backendStoreActions.saveCurrentNode(store)
store.deleteCurrentNode = backendStoreActions.deleteCurrentNode(store)
store.saveField = backendStoreActions.saveField(store)
store.deleteField = backendStoreActions.deleteField(store)
store.importAppDefinition = importAppDefinition(store) store.importAppDefinition = importAppDefinition(store)
store.deleteCurrentNode = deleteCurrentNode(store)
store.saveField = saveField(store)
store.deleteField = deleteField(store)
store.saveAction = saveAction(store) store.saveAction = saveAction(store)
store.deleteAction = deleteAction(store) store.deleteAction = deleteAction(store)
store.saveTrigger = saveTrigger(store) store.saveTrigger = saveTrigger(store)
@ -245,101 +247,12 @@ const showSettings = store => () => {
} }
const useAnalytics = store => () => { const useAnalytics = store => () => {
store.update(s => { store.update(state => {
s.useAnalytics = !s.useAnalytics state.useAnalytics = !s.useAnalytics
return s return state
})
}
const newRecord = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
const parent = useRoot
? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId)
s.errors = []
s.currentNode = templateApi(shadowHierarchy).getNewRecordTemplate(
parent,
"",
true
)
return s
})
}
const selectExistingNode = store => nodeId => {
store.update(s => {
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
s.currentNode = getNode(shadowHierarchy, nodeId)
s.currentNodeIsNew = false
s.errors = []
return s
})
}
const newIndex = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true
s.errors = []
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
const parent = useRoot
? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId)
s.currentNode = templateApi(shadowHierarchy).getNewIndexTemplate(parent)
return s
}) })
} }
const saveCurrentNode = store => () => {
store.update(s => {
const errors = validate.node(s.currentNode)
s.errors = errors
if (errors.length > 0) {
return s
}
const parentNode = getNode(s.hierarchy, s.currentNode.parent().nodeId)
const existingNode = getNode(s.hierarchy, s.currentNode.nodeId)
let index = parentNode.children.length
if (existingNode) {
// remove existing
index = existingNode.parent().children.indexOf(existingNode)
existingNode.parent().children = pipe(existingNode.parent().children, [
filter(c => c.nodeId !== existingNode.nodeId),
])
}
// should add node into existing hierarchy
const cloned = cloneDeep(s.currentNode)
templateApi(s.hierarchy).constructNode(parentNode, cloned)
const newIndexOfChild = child => {
if (child === cloned) return index
const currentIndex = parentNode.children.indexOf(child)
return currentIndex >= index ? currentIndex + 1 : currentIndex
}
parentNode.children = pipe(parentNode.children, [sortBy(newIndexOfChild)])
if (!existingNode && s.currentNode.type === "record") {
const defaultIndex = templateApi(s.hierarchy).getNewIndexTemplate(
cloned.parent()
)
defaultIndex.name = `all_${cloned.collectionName}`
defaultIndex.allowedRecordNodeIds = [cloned.nodeId]
}
s.currentNodeIsNew = false
saveBackend(s)
return s
})
}
const importAppDefinition = store => appDefinition => { const importAppDefinition = store => appDefinition => {
store.update(s => { store.update(s => {
@ -355,48 +268,6 @@ const importAppDefinition = store => appDefinition => {
}) })
} }
const deleteCurrentNode = store => () => {
store.update(s => {
const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId)
s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
? find(n => n != s.currentNode)(s.hierarchy.children)
: nodeToDelete.parent()
if (hierarchyFunctions.isRecord(nodeToDelete)) {
nodeToDelete.parent().children = filter(
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().children)
} else {
nodeToDelete.parent().indexes = filter(
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().indexes)
}
s.errors = []
saveBackend(s)
return s
})
}
const saveField = databaseStore => field => {
databaseStore.update(db => {
db.currentNode.fields = filter(f => f.name !== field.name)(
db.currentNode.fields
)
templateApi(db.hierarchy).addField(db.currentNode, field)
return db
})
}
const deleteField = databaseStore => field => {
databaseStore.update(db => {
db.currentNode.fields = filter(f => f.name !== field.name)(
db.currentNode.fields
)
return db
})
}
const saveAction = store => (newAction, isNew, oldAction = null) => { const saveAction = store => (newAction, isNew, oldAction = null) => {
store.update(s => { store.update(s => {
const existingAction = isNew const existingAction = isNew
@ -526,32 +397,6 @@ const _saveScreen = async (store, s, screen) => {
return innerState return innerState
}) })
/*const updatedScreen = await savedScreen.json()
const screens = [
...currentPageScreens.filter(
storeScreen => storeScreen.name !== updatedScreen.name
),
updatedScreen,
]
store.update(innerState => {
innerState.pages[s.currentPageName]._screens = screens
innerState.screens = screens
let curentComponentId
walkProps(screen.props, p => {
if(p === innerState.currentComponentInfo)
currentComponentId = p._id
})
innerState.currentPreviewItem = updatedScreen
innerState.currentComponentInfo = makePropsSafe(componentDef, component)
_savePage(innerState)
return innerState
})
*/
}) })
return s return s
@ -761,17 +606,6 @@ const _savePage = async s => {
}) })
} }
const saveBackend = async state => {
await api.post(`/_builder/api/${appname}/backend`, {
appDefinition: {
hierarchy: state.hierarchy,
actions: state.actions,
triggers: state.triggers,
},
accessLevels: state.accessLevels,
})
}
const setCurrentPage = store => pageName => { const setCurrentPage = store => pageName => {
store.update(s => { store.update(s => {
const current_screens = s.pages[pageName]._screens const current_screens = s.pages[pageName]._screens
@ -801,9 +635,6 @@ const setCurrentPage = store => pageName => {
}) })
} }
const getContainerComponent = components =>
getComponentDefinition(components, "@budibase/standard-components/container")
const getComponentDefinition = (components, name) => const getComponentDefinition = (components, name) =>
components.find(c => c.name === name) components.find(c => c.name === name)

15
packages/builder/src/database/ActionsHeader.svelte

@ -14,19 +14,22 @@
confirmDelete = true confirmDelete = true
} }
// const deleteCurrentNode = () => {
// confirmDelete = false
// store.deleteCurrentNode()
// }
// TODO: COMPLETELY REFACTOR THIS SHIT
const deleteCurrentNode = () => { const deleteCurrentNode = () => {
confirmDelete = false confirmDelete = false
store.deleteCurrentNode() store.deleteCurrentNode()
} }
</script> </script>
<div class="root" style="left: {left}"> <div class="root">
<ButtonGroup> <ButtonGroup>
<ActionButton <ActionButton color="secondary" grouped on:click={store.saveCurrentNode}>
color="secondary" Save
grouped
on:click={store.saveCurrentNode}>
{#if $store.currentNodeIsNew}Create{:else}Update{/if}
</ActionButton> </ActionButton>
{#if !$store.currentNodeIsNew} {#if !$store.currentNodeIsNew}

71
packages/builder/src/database/DatabaseRoot.svelte

@ -7,61 +7,34 @@
import { store } from "../builderStore" import { store } from "../builderStore"
import getIcon from "../common/icon" import getIcon from "../common/icon"
import DropdownButton from "../common/DropdownButton.svelte" import DropdownButton from "../common/DropdownButton.svelte"
import ActionButton from "../common/ActionButton.svelte"
import Modal from "../common/Modal.svelte" import Modal from "../common/Modal.svelte"
import { hierarchy as hierarchyFunctions } from "../../../core/src" import { CreateEditRecordModal } from "./ModelDataTable/modals"
const hierarchyWidth = "200px" let modalOpen
let selectedRecord
const defaultNewIndexActions = [ function selectRecord(record) {
{ selectedRecord = record
label: "New Root Index", modalOpen = true
onclick: store.newRootIndex, }
},
]
const defaultNewRecordActions = [
{
label: "New Root Record",
onclick: store.newRootRecord,
},
]
let newIndexActions = defaultNewIndexActions
let newRecordActions = defaultNewRecordActions
store.subscribe(db => {
if (!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) {
newRecordActions = defaultNewRecordActions
newIndexActions = defaultNewIndexActions
} else {
newRecordActions = [
...defaultNewRecordActions,
{
label: `New Child Record of ${db.currentNode.name}`,
onclick: store.newChildRecord,
},
]
newIndexActions = [
...defaultNewIndexActions,
{
label: `New Index on ${db.currentNode.name}`,
onclick: store.newChildIndex,
},
]
}
})
</script> </script>
<CreateEditRecordModal bind:modalOpen record={selectedRecord} />
<!-- <DeleteRecordModal modalOpen={deleteRecordModal} record={selectedRecord} /> -->
<div class="root"> <div class="root">
<!-- <div class="actions-header">
{#if $store.currentNode}
<ActionsHeader />
{/if}
</div> -->
<div class="node-view"> <div class="node-view">
<div class="breadcrumbs">{$store.currentlySelectedDatabase}</div> <div class="breadcrumbs">{$store.currentlySelectedDatabase}</div>
<ModelDataTable /> <ActionButton
primary
on:click={() => {
selectedRecord = null
modalOpen = true
}}>
Create new record
</ActionButton>
<ModelDataTable {selectRecord} />
{#if $store.currentNode} {#if $store.currentNode}
<Modal isOpen={$store.currentNode}> <Modal isOpen={$store.currentNode}>
{#if $store.currentNode.type === 'record'} {#if $store.currentNode.type === 'record'}
@ -82,10 +55,6 @@
position: relative; position: relative;
} }
.actions-header {
flex: 0 1 auto;
}
.node-view { .node-view {
overflow-y: auto; overflow-y: auto;
flex: 1 1 auto; flex: 1 1 auto;

5
packages/builder/src/database/IndexView.svelte

@ -110,11 +110,6 @@
margin-right: 30px; margin-right: 30px;
} }
.index-label {
color: #333;
font-size: 0.875rem;
}
.snippet-selector__heading { .snippet-selector__heading {
margin-right: 20px; margin-right: 20px;
opacity: 0.7; opacity: 0.7;

62
packages/builder/src/database/ModelDataTable/ModelDataTable.svelte

@ -1,43 +1,53 @@
<script> <script>
import { onMount } from "svelte"
import { store } from "../../builderStore" import { store } from "../../builderStore"
import Select from "../../common/Select.svelte" import Select from "../../common/Select.svelte"
import { CreateEditRecordModal, DeleteRecordModal } from "./modals" import { getIndexSchema } from "../../common/core"
import ActionButton from "../../common/ActionButton.svelte" import ActionButton from "../../common/ActionButton.svelte"
import TablePagination from "./TablePagination.svelte" import TablePagination from "./TablePagination.svelte"
import { DeleteRecordModal } from "./modals"
import * as api from "./api" import * as api from "./api"
import { getIndexSchema } from "../../common/core"
let pages = [1, 2, 3] export let selectRecord
export let data = [
{ name: "Joe", inStock: true },
{ name: "Mike", inStock: false },
{ name: "Martin", inStock: true },
]
export let headers = ["name", "inStock"]
// export let pageSize = 10
let pages = [1, 2, 3]
let selectedView = "" let selectedView = ""
let modalOpen = false let modalOpen = false
let deleteRecordModal = false let deleteRecordModal = false
let data = []
let headers = []
let selectedRecord
$: indexes = $store.hierarchy.indexes $: views = $store.hierarchy.indexes
$: currentAppInfo = {
appname: $store.appname,
instanceId: $store.currentInstanceId
}
const getSchema = getIndexSchema($store.hierarchy) const getSchema = getIndexSchema($store.hierarchy)
async function fetchRecordsForView(viewName) {
const recordsForIndex = await api.fetchDataForView(viewName, currentAppInfo)
data = recordsForIndex
headers = Object.keys(data[0])
}
onMount(async () => {
await fetchRecordsForView(views[0].name, currentAppInfo)
})
</script> </script>
<CreateEditRecordModal bind:modalOpen /> <DeleteRecordModal modalOpen={deleteRecordModal} record={selectedRecord} />
<DeleteRecordModal modalOpen={deleteRecordModal} />
<section> <section>
<div class="table-controls"> <div class="table-controls">
<h4 class="budibase__title--3">Shoe database</h4> <h4 class="budibase__title--3">Shoe database</h4>
<Select <Select
icon="ri-eye-line" icon="ri-eye-line"
on:change={e => api.fetchDataForView(e.target.value)}> on:change={e => fetchRecordsForView(e.target.value)}>
{#each indexes as index} {#each views as view}
({console.log(getSchema(index))}) <!-- ({console.log(getSchema(view))}) ({console.log(view)}) -->
<option value={index.name}>{index.name}</option> <option value={view.name}>{view.name}</option>
{/each} {/each}
</Select> </Select>
</div> </div>
@ -61,11 +71,18 @@
<li> <li>
<div>View</div> <div>View</div>
</li> </li>
<li> <li
<div on:click={() => (modalOpen = true)}>Edit</div> on:click={() => selectRecord(row)}>
<div>Edit</div>
</li> </li>
<li> <li>
<div on:click={() => (deleteRecordModal = true)}>Delete</div> <div
on:click={() => {
deleteRecordModal = true
selectedRecord = row
}}>
Delete
</div>
</li> </li>
<li> <li>
<div>Duplicate</div> <div>Duplicate</div>
@ -111,7 +128,8 @@
align-items: center; align-items: center;
} }
.ri-more-line:hover, .uk-dropdown-nav li:hover{ .ri-more-line:hover,
.uk-dropdown-nav li:hover {
cursor: pointer; cursor: pointer;
} }
</style> </style>

26
packages/builder/src/database/ModelDataTable/api.js

@ -1,24 +1,26 @@
import api from "../../builderStore/api"; import api from "../../builderStore/api";
import { getNewRecord } from "../../common/core"
export async function deleteRecord(appName, appInstanceId, record) { export async function deleteRecord(record, { appname, instanceId }) {
const DELETE_RECORDS_URL = `/_builder/instance/${appName}/${appInstanceId}/api/record/${record.name}/${record.id}` const DELETE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record/${record.name}/${record.id}`
const response = await api.delete({ const response = await api.delete({
url: DELETE_RECORDS_URL url: DELETE_RECORDS_URL
}); });
return response;
} }
export async function createNewRecord(record) { export async function saveRecord(record, { appname, instanceId }) {
console.log(record); const SAVE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record`
const updatedRecord = getNewRecord(record, "")
const response = await api.post(SAVE_RECORDS_URL, updatedRecord)
return response
} }
export async function fetchDataForView(viewName) { export async function fetchDataForView(viewName, { appname, instanceId }) {
console.log(viewName); const FETCH_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/listRecords/${viewName}`;
// const FETCH_RECORDS_URL = `/_builder/instance/${}/${}/api/listRecords/`
// const response = await api.get({ url: FETCH_RECORDS_URL }); // TODO: Error handling
const response = await api.get(FETCH_RECORDS_URL);
// console.log(response); return await response.json();
// GET /_builder/instance/:appname/:instanceid/api/listRecords/contacts/abcd1234/all_deals
} }

2
packages/builder/src/database/ModelDataTable/modals/CreateEditModel.svelte

@ -11,7 +11,7 @@
</script> </script>
<Modal {onClosed} bind:isOpen={modalOpen} title={'Record'}> <Modal {onClosed} bind:isOpen={modalOpen} title={'Record'}>
<h4 class="budibase__title--4">Create / Edit Record</h4> <h4 class="budibase__title--4">Create / Edit Model</h4>
<div class="actions"> <div class="actions">
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton <ActionButton

108
packages/builder/src/database/ModelDataTable/modals/CreateEditRecord.svelte

@ -1,60 +1,84 @@
<script> <script>
import { onMount } from "svelte"
import { store } from "../../../builderStore"
import Modal from "../../../common/Modal.svelte" import Modal from "../../../common/Modal.svelte"
import ActionButton from "../../../common/ActionButton.svelte" import ActionButton from "../../../common/ActionButton.svelte"
import Select from "../../../common/Select.svelte"
import * as api from "../api" import * as api from "../api"
export let modalOpen = false export let modalOpen = false
export let model = {} export let record
let selectedModel
$: currentAppInfo = {
instanceId: $store.currentInstanceId,
appname: $store.appname,
}
$: recordFields = record ? Object.keys(record) : []
$: models = $store.hierarchy.children
$: modelFields = selectedModel
? selectedModel.fields.map(({ name }) => name)
: []
const onClosed = () => (modalOpen = false) const onClosed = () => (modalOpen = false)
</script> </script>
<Modal {onClosed} bind:isOpen={modalOpen} title={'Record'}> <Modal {onClosed} isOpen={modalOpen}>
<h4 class="budibase__title--4">Create / Edit Record</h4> <h4 class="budibase__title--4">Create / Edit Record</h4>
<div class="actions"> <div class="actions">
<form> {console.log('record', record)}
<div class="uk-margin"> {console.log('selectedModel', selectedModel)}
<label class="uk-form-label" for="form-stacked-text">Text</label> {console.log('recordFields', recordFields)}
<div class="uk-form-controls"> <form class="uk-form-stacked">
<input {#if !record}
class="uk-input" <div class="uk-margin">
id="form-stacked-text" <label class="uk-form-label" for="form-stacked-text">Model</label>
type="text" <Select bind:value={selectedModel}>
placeholder="Some text..." /> {#each models as model}
<option value={model}>{model.name}</option>
{/each}
</Select>
</div> </div>
</div> {/if}
{#each modelFields as field}
<div class="uk-margin"> <div class="uk-margin">
<label class="uk-form-label" for="form-stacked-select">Select</label> <label class="uk-form-label" for="form-stacked-text">{field}</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<select class="uk-select" id="form-stacked-select"> <input
<option>Option 01</option> class="uk-input"
<option>Option 02</option> id="form-stacked-text"
</select> type="text"
bind:value={selectedModel[field]} />
</div>
</div> </div>
</div> {/each}
{#each recordFields as field}
<div class="uk-margin"> <div class="uk-margin">
<div class="uk-form-label">Radio</div> <label class="uk-form-label" for="form-stacked-text">{field}</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<label> <input
<input class="uk-radio" type="radio" name="radio1" /> class="uk-input"
Option 01 id="form-stacked-text"
</label> type="text"
<br /> bind:value={record[field]} />
<label> </div>
<input class="uk-radio" type="radio" name="radio1" />
Option 02
</label>
</div> </div>
</div> {/each}
</form> </form>
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <div class="actions">
<ActionButton <ActionButton alert on:click={onClosed}>Cancel</ActionButton>
disabled={false} <ActionButton
on:click={() => api.createNewRecord(recordInfo)}> disabled={false}
Save on:click={() => api.saveRecord(record || selectedModel, currentAppInfo)}>
</ActionButton> Save
</ActionButton>
</div>
</div> </div>
</Modal> </Modal>
<style>
.actions {
position: absolute;
}
</style>

10
packages/builder/src/database/ModelDataTable/modals/DeleteRecord.svelte

@ -4,20 +4,22 @@
import * as api from "../api" import * as api from "../api"
export let modalOpen = false export let modalOpen = false
export let record
let recordInfo = {}
const onClosed = () => (modalOpen = false) const onClosed = () => (modalOpen = false)
</script> </script>
<Modal {onClosed} bind:isOpen={modalOpen} title={"Delete Record?"}> <Modal {onClosed} bind:isOpen={modalOpen}>
<h4 class="budibase__title--4">Delete Record</h4> <h4 class="budibase__title--4">Delete Record</h4>
Are you sure you want to delete this record? All of your data will be permanently removed. This action cannot be undone. Are you sure you want to delete this record? All of your data will be permanently removed. This action cannot be undone.
<div class="modal-actions"> <div class="modal-actions">
<ActionButton on:click={onClosed}>Cancel</ActionButton> <ActionButton on:click={onClosed}>Cancel</ActionButton>
<ActionButton <ActionButton
alert alert
on:click={() => api.deleteRecord(recordInfo)}> on:click={async () => {
await api.deleteRecord(record)
onClosed();
}}>
Delete Delete
</ActionButton> </ActionButton>
</div> </div>

5
packages/builder/src/database/ModelView.svelte

@ -139,7 +139,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each record.fields as field} {#each record ? record.fields : [] as field}
<tr> <tr>
<td> <td>
<i class="ri-more-line" on:click={() => editField(field)} /> <i class="ri-more-line" on:click={() => editField(field)} />
@ -150,9 +150,6 @@
<td>{field.type}</td> <td>{field.type}</td>
<td>({console.log(field.typeOptions)}) {field.typeOptions.values}</td> <td>({console.log(field.typeOptions)}) {field.typeOptions.values}</td>
<td> <td>
<!-- <span class="edit-button" on:click={() => editField(field)}>
{@html getIcon('edit')}
</span> -->
<span class="edit-button" on:click={() => deleteField(field)}> <span class="edit-button" on:click={() => deleteField(field)}>
{@html getIcon('trash')} {@html getIcon('trash')}
</span> </span>

2
packages/builder/src/nav/DatabasesList.svelte

@ -1,5 +1,4 @@
<script> <script>
import { navigate } from "svelte-routing"
import { store } from "../builderStore" import { store } from "../builderStore"
import getIcon from "../common/icon" import getIcon from "../common/icon"
import { CheckIcon } from "../common/Icons" import { CheckIcon } from "../common/Icons"
@ -11,7 +10,6 @@
state.currentlySelectedDatabase = databaseId state.currentlySelectedDatabase = databaseId
return state return state
}) })
navigate("/database", { replace: true })
} }
</script> </script>

6
packages/builder/src/nav/SchemaManagementDrawer.svelte

@ -71,13 +71,13 @@
<div class="nav-group-header"> <div class="nav-group-header">
<div class="hierarchy-title">Schema</div> <div class="hierarchy-title">Schema</div>
<div class="uk-inline"> <div class="uk-inline">
<i class="ri-add-line" /> <i class="ri-add-line hoverable" />
<div uk-dropdown="mode: click"> <div uk-dropdown="mode: click">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<li> <li class="hoverable" on:click={() => {}}>
Model Model
</li> </li>
<li> <li class="hoverable" on:click={() => {}}>
View View
</li> </li>
</ul> </ul>

0
packages/client/src/state/stateManager/dynamicPropertySource.js

5
packages/core/src/recordApi/getNew.js

@ -22,6 +22,11 @@ export const getNew = app => (collectionKey, recordTypeName) => {
) )
} }
/**
* Constructs a record object that can be saved to the backend.
* @param {*} recordNode - record
* @param {*} collectionKey - nested collection key that the record will be saved to.
*/
export const _getNew = (recordNode, collectionKey) => export const _getNew = (recordNode, collectionKey) =>
constructRecord(recordNode, getNewFieldValue, collectionKey) constructRecord(recordNode, getNewFieldValue, collectionKey)

Loading…
Cancel
Save