moving more backend stuff into other store actions file

This commit is contained in:
Martin McKeaveney 2020-03-22 11:35:35 +00:00
parent b474f8a600
commit 266c36f079
12 changed files with 166 additions and 221 deletions

View File

@ -34,7 +34,7 @@ export const getBackendUiStore = () => {
store.actions = { store.actions = {
navigate: name => store.update(state => ({ ...state, leftNavItem: name })), navigate: name => store.update(state => ({ ...state, leftNavItem: name })),
database: { database: {
select: db => store.update(state => ({ ...state, selectedDatabase: db })), select: state => store.update(state => ({ ...state, selectedDatabase: state })),
}, },
records: { records: {
delete: record => store.update(state => { delete: record => store.update(state => {
@ -96,8 +96,7 @@ export const newRecord = (store, useRoot) => () => {
export const selectExistingNode = store => nodeId => { export const selectExistingNode = store => nodeId => {
store.update(state => { store.update(state => {
const shadowHierarchy = createShadowHierarchy(state.hierarchy) state.currentNode = getNode(state.hierarchy, nodeId)
state.currentNode = getNode(shadowHierarchy, nodeId)
state.currentNodeIsNew = false state.currentNodeIsNew = false
state.errors = [] state.errors = []
return state return state
@ -179,42 +178,32 @@ export const deleteCurrentNode = store => () => {
node => node.nodeId === nodeToDelete.nodeId node => node.nodeId === nodeToDelete.nodeId
) )
// if (hierarchyFunctions.isRecord(nodeToDelete)) {
// nodeToDelete.parent().children = filter(
// c => c.nodeId !== nodeToDelete.nodeId
// )(nodeToDelete.parent().children)
// } else {
// nodeToDelete.parent().indexes = remove(
// nodeToDelete.parent().indexes,
// node => node.nodeId === nodeToDelete.nodeId
// )
// }
state.errors = [] state.errors = []
saveBackend(state) saveBackend(state)
return state return state
}) })
} }
export const saveField = databaseStore => field => { export const saveField = store => field => {
databaseStore.update(db => { store.update(state => {
db.currentNode.fields = filter(f => f.name !== field.name)( state.currentNode.fields = state.currentNode.fields.filter(f => f.name !== field.name)
db.currentNode.fields
)
templateApi(db.hierarchy).addField(db.currentNode, field) templateApi(state.hierarchy).addField(state.currentNode, field)
return db return state
}) })
} }
export const deleteField = databaseStore => field => { export const deleteField = store => field => {
databaseStore.update(db => { store.update(state => {
db.currentNode.fields = db.currentNode.fields.filter(f => f.name !== field.name) state.currentNode.fields = state.currentNode.fields.filter(f => f.name !== field.name)
return db return state
}) })
} }
const incrementAccessLevelsVersion = state => const incrementAccessLevelsVersion = state => {
(state.accessLevels.version = (state.accessLevels.version || 0) + 1) state.accessLevels.version = state.accessLevels.version ? state.accessLevels.version + 1 : 1
return state
}
export const saveLevel = store => (newLevel, isNew, oldLevel = null) => { export const saveLevel = store => (newLevel, isNew, oldLevel = null) => {
store.update(state => { store.update(state => {
@ -247,3 +236,52 @@ export const deleteLevel = store => level => {
return state return state
}) })
} }
export const saveAction = store => (newAction, isNew, oldAction = null) => {
store.update(s => {
const existingAction = isNew
? null
: find(a => a.name === oldAction.name)(s.actions)
if (existingAction) {
s.actions = s.actions.map(action => action === existingAction ? newAction : action)
} else {
s.actions.push(newAction)
}
saveBackend(s)
return s
})
}
export const deleteAction = store => action => {
store.update(state => {
state.actions = state.actions.filter(a => a.name !== action.name);
saveBackend(state);
return state;
})
}
export const saveTrigger = store => (newTrigger, isNew, oldTrigger = null) => {
store.update(s => {
const existingTrigger = isNew
? null
: find(a => a.name === oldTrigger.name)(s.triggers)
if (existingTrigger) {
s.triggers = pipe(s.triggers, [
map(a => (a === existingTrigger ? newTrigger : a)),
])
} else {
s.triggers.push(newTrigger)
}
saveBackend(s)
return s
})
}
export const deleteTrigger = store => trigger => {
store.update(s => {
s.triggers = filter(t => t.name !== trigger.name)(s.triggers)
return s
})
}

View File

@ -1,10 +1,8 @@
import { import {
filter, filter,
cloneDeep, cloneDeep,
map,
last, last,
concat, concat,
find,
isEmpty, isEmpty,
values, values,
} from "lodash/fp" } from "lodash/fp"
@ -76,12 +74,12 @@ export const getStore = () => {
store.saveLevel = backendStoreActions.saveLevel(store) store.saveLevel = backendStoreActions.saveLevel(store)
store.deleteLevel = backendStoreActions.deleteLevel(store) store.deleteLevel = backendStoreActions.deleteLevel(store)
store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store) store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store)
store.saveAction = backendStoreActions.saveAction(store)
store.deleteAction = backendStoreActions.deleteAction(store)
store.saveTrigger = backendStoreActions.saveTrigger(store)
store.deleteTrigger = backendStoreActions.deleteTrigger(store)
store.importAppDefinition = importAppDefinition(store) store.importAppDefinition = importAppDefinition(store)
store.saveAction = saveAction(store)
store.deleteAction = deleteAction(store)
store.saveTrigger = saveTrigger(store)
store.deleteTrigger = deleteTrigger(store)
store.saveScreen = saveScreen(store) store.saveScreen = saveScreen(store)
store.addComponentLibrary = addComponentLibrary(store) store.addComponentLibrary = addComponentLibrary(store)
store.renameScreen = renameScreen(store) store.renameScreen = renameScreen(store)
@ -154,10 +152,6 @@ const initialise = (store, initial) => async () => {
} }
initial.appname = appname initial.appname = appname
initial.pages = pkg.pages initial.pages = pkg.pages
initial.currentInstanceId =
pkg.application.instances && pkg.application.instances.length > 0
? pkg.application.instances[0].id
: ""
initial.hasAppPackage = true initial.hasAppPackage = true
initial.hierarchy = pkg.appDefinition.hierarchy initial.hierarchy = pkg.appDefinition.hierarchy
initial.accessLevels = pkg.accessLevels initial.accessLevels = pkg.accessLevels
@ -174,9 +168,10 @@ const initialise = (store, initial) => async () => {
if (!!initial.hierarchy && !isEmpty(initial.hierarchy)) { if (!!initial.hierarchy && !isEmpty(initial.hierarchy)) {
initial.hierarchy = constructHierarchy(initial.hierarchy) initial.hierarchy = constructHierarchy(initial.hierarchy)
const shadowHierarchy = createShadowHierarchy(initial.hierarchy) const shadowHierarchy = createShadowHierarchy(initial.hierarchy)
if (initial.currentNode !== null) if (initial.currentNode !== null) {
initial.currentNode = getNode(shadowHierarchy, initial.currentNode.nodeId) initial.currentNode = getNode(shadowHierarchy, initial.currentNode.nodeId)
} }
}
store.set(initial) store.set(initial)
return initial return initial
@ -191,7 +186,7 @@ const showSettings = store => () => {
const useAnalytics = store => () => { const useAnalytics = store => () => {
store.update(state => { store.update(state => {
state.useAnalytics = !s.useAnalytics state.useAnalytics = !state.useAnalytics
return state return state
}) })
} }
@ -211,56 +206,6 @@ const importAppDefinition = store => appDefinition => {
}) })
} }
const saveAction = store => (newAction, isNew, oldAction = null) => {
store.update(s => {
const existingAction = isNew
? null
: find(a => a.name === oldAction.name)(s.actions)
if (existingAction) {
s.actions = pipe(s.actions, [
map(a => (a === existingAction ? newAction : a)),
])
} else {
s.actions.push(newAction)
}
saveBackend(s)
return s
})
}
const deleteAction = store => action => {
store.update(state => {
state.actions = state.actions.filter(a => a.name !== action.name);
saveBackend(state);
return state;
})
}
const saveTrigger = store => (newTrigger, isNew, oldTrigger = null) => {
store.update(s => {
const existingTrigger = isNew
? null
: find(a => a.name === oldTrigger.name)(s.triggers)
if (existingTrigger) {
s.triggers = pipe(s.triggers, [
map(a => (a === existingTrigger ? newTrigger : a)),
])
} else {
s.triggers.push(newTrigger)
}
saveBackend(s)
return s
})
}
const deleteTrigger = store => trigger => {
store.update(s => {
s.triggers = filter(t => t.name !== trigger.name)(s.triggers)
return s
})
}
const createShadowHierarchy = hierarchy => const createShadowHierarchy = hierarchy =>
constructHierarchy(JSON.parse(JSON.stringify(hierarchy))) constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))

View File

@ -1,45 +0,0 @@
<script>
export let data = []
export let headers = []
</script>
<table class="uk-table">
<thead>
<tr>
<th>Edit</th>
{#each headers as header}
<th>{header}</th>
{/each}
</tr>
</thead>
<tbody>
{#each data as row}
<tr>
<td>
<div class="uk-inline">
<i class="ri-more-line" />
<div uk-dropdown="mode: click">
<ul class="uk-nav uk-dropdown-nav">
<li>
<div>View</div>
</li>
<li>
<div>Edit</div>
</li>
<li>
<div on:click={() => (deleteRecordModal = true)}>Delete</div>
</li>
<li>
<div>Duplicate</div>
</li>
</ul>
</div>
</div>
</td>
{#each headers as header}
<td>{row[header]}</td>
{/each}
</tr>
{/each}
</tbody>
</table>

View File

@ -25,6 +25,6 @@
<style> <style>
textarea { textarea {
width: 300px; width: 300px;
height: 200px; height: 100px;
} }
</style> </style>

View File

@ -31,6 +31,7 @@
$: viewOpen = $backendUiStore.visibleModal === "VIEW" $: viewOpen = $backendUiStore.visibleModal === "VIEW"
$: databaseOpen = $backendUiStore.visibleModal === "DATABASE" $: databaseOpen = $backendUiStore.visibleModal === "DATABASE"
$: deleteRecordOpen = $backendUiStore.visibleModal === "DELETE_RECORD" $: deleteRecordOpen = $backendUiStore.visibleModal === "DELETE_RECORD"
$: breadcrumbs = $store.currentNode
</script> </script>
<Modal isOpen={!!$backendUiStore.visibleModal} {onClosed}> <Modal isOpen={!!$backendUiStore.visibleModal} {onClosed}>
@ -47,7 +48,7 @@
<CreateDatabaseModal {onClosed} /> <CreateDatabaseModal {onClosed} />
{/if} {/if}
{#if deleteRecordOpen} {#if deleteRecordOpen}
<DeleteRecordModal record={selectedRecord} /> <DeleteRecordModal record={selectedRecord} {onClosed} />
{/if} {/if}
</Modal> </Modal>
@ -57,9 +58,10 @@
<div class="database-actions"> <div class="database-actions">
<div class="budibase__label--big"> <div class="budibase__label--big">
{#if $backendUiStore.selectedDatabase.name} {#if $backendUiStore.selectedDatabase.name}
{$backendUiStore.selectedDatabase.name} / {$store.currentNode} {$backendUiStore.selectedDatabase.name} {breadcrumbs}
{/if} {/if}
</div> </div>
{#if $backendUiStore.selectedDatabase.id}
<ActionButton <ActionButton
primary primary
on:click={() => { on:click={() => {
@ -68,6 +70,7 @@
}}> }}>
Create new record Create new record
</ActionButton> </ActionButton>
{/if}
</div> </div>
<ModelDataTable {selectRecord} /> <ModelDataTable {selectRecord} />
</div> </div>

View File

@ -27,9 +27,9 @@
hierarchyFunctions.getFlattenedHierarchy, hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isDecendant(index.parent())), filter(hierarchyFunctions.isDecendant(index.parent())),
filter(hierarchyFunctions.isRecord), filter(hierarchyFunctions.isRecord),
map(n => ({ map(node => ({
node: n, node,
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds), isallowed: index.allowedRecordNodeIds.some(id => node.nodeId === id),
})), })),
] ]
) )
@ -37,19 +37,17 @@
const toggleAllowedRecord = record => { const toggleAllowedRecord = record => {
if (record.isallowed) { if (record.isallowed) {
index.allowedRecordNodeIds = filter(id => id !== record.node.nodeId)( index.allowedRecordNodeIds = index.allowedRecordNodeIds.filter(id => id !== record.node.nodeId)
index.allowedRecordNodeIds
)
} else { } else {
index.allowedRecordNodeIds.push(record.node.nodeId) index.allowedRecordNodeIds.push(record.node.nodeId)
} }
} }
</script> </script>
<h3 class="budibase__title--3"> <heading>
<i class="ri-eye-line" /> <i class="ri-eye-line button--toggled" />
Create / Edit View <h3 class="budibase__title--3">Create / Edit View</h3>
</h3> </heading>
<form class="uk-form-stacked root"> <form class="uk-form-stacked root">
<h4 class="budibase__label--big">Settings</h4> <h4 class="budibase__label--big">Settings</h4>
<div class="uk-grid-small" uk-grid> <div class="uk-grid-small" uk-grid>
@ -70,10 +68,11 @@
</div> </div>
{#each indexableRecords as rec} {#each indexableRecords as rec}
<input <input
class="uk-checkbox"
type="checkbox" type="checkbox"
checked={rec.isallowed} checked={rec.isallowed}
on:change={() => toggleAllowedRecord(rec)} /> on:change={() => toggleAllowedRecord(rec)} />
<span>{rec.node.name}</span> <span class="checkbox-model-label">{rec.node.name}</span>
{/each} {/each}
</div> </div>
@ -118,4 +117,17 @@
.highlighted { .highlighted {
opacity: 1; opacity: 1;
} }
.checkbox-model-label {
text-transform: capitalize;
}
h3 {
margin: 0 0 0 10px;
}
heading {
display: flex;
align-items: center;
}
</style> </style>

View File

@ -10,7 +10,7 @@
export let selectRecord export let selectRecord
const ITEMS_PER_PAGE = 2 const ITEMS_PER_PAGE = 10
let selectedView = "" let selectedView = ""
let modalOpen = false let modalOpen = false
@ -21,12 +21,13 @@
$: views = $store.hierarchy.indexes $: views = $store.hierarchy.indexes
$: currentAppInfo = { $: currentAppInfo = {
appname: $store.appname, appname: $store.appname,
instanceId: $store.currentInstanceId, instanceId: $backendUiStore.selectedDatabase.id
} }
$: data = $backendUiStore.selectedView.records.slice( $: data = $backendUiStore.selectedView.records.slice(
currentPage * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE,
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
) )
$: showTable = currentAppInfo.instanceId && views.length > 0
const getSchema = getIndexSchema($store.hierarchy) const getSchema = getIndexSchema($store.hierarchy)
@ -42,13 +43,13 @@
} }
onMount(async () => { onMount(async () => {
if (views.length > 0) { if (showTable) {
await fetchRecordsForView(views[0].name, currentAppInfo) await fetchRecordsForView(views[0].name, currentAppInfo)
} }
}) })
</script> </script>
{#if views.length > 0} {#if showTable}
<section> <section>
<div class="table-controls"> <div class="table-controls">
<h4 class="budibase__title--3">{$backendUiStore.selectedDatabase.name || ""}</h4> <h4 class="budibase__title--3">{$backendUiStore.selectedDatabase.name || ""}</h4>
@ -80,6 +81,14 @@
<i class="ri-more-line" /> <i class="ri-more-line" />
<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>
<div
on:click={async () => {
// fetch the child records for that particular row
}}>
View
</div>
</li>
<li <li
on:click={() => { on:click={() => {
selectRecord(row) selectRecord(row)
@ -98,8 +107,8 @@
</li> </li>
<li> <li>
<div <div
on:click={() => { on:click={async () => {
console.log("DUPLICATION") const response = await api.saveRecord(row)
}}> }}>
Duplicate Duplicate
</div> </div>
@ -118,7 +127,7 @@
<TablePagination bind:currentPage pageItemCount={data.length} {ITEMS_PER_PAGE} /> <TablePagination bind:currentPage pageItemCount={data.length} {ITEMS_PER_PAGE} />
</section> </section>
{:else} {:else}
Please create a model to get started. Please select a database.
{/if} {/if}

View File

@ -21,12 +21,22 @@
if (record.collectionName) { if (record.collectionName) {
const collectionKey = `/${record.collectionName}` const collectionKey = `/${record.collectionName}`
recordBase = getNewRecord(recordBase, collectionKey) recordBase = getNewRecord(recordBase, collectionKey)
// overwrite the new record template values recordBase = overwritePresentProperties(recordBase, record)
for (let key in recordBase) {
if (record[key]) recordBase[key] = record[key]
} }
const SAVE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record/`
const response = await api.post(SAVE_RECORDS_URL, recordBase)
return await response.json()
} }
export async function duplicateRecord(record, { appname, instanceId }) {
let recordBase = { ...record }
delete recordBase.id
recordBase = getNewRecord(recordBase, recordBase.key)
recordBase = overwritePresentProperties(recordBase, record)
const SAVE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record/` const SAVE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record/`
const response = await api.post(SAVE_RECORDS_URL, recordBase) const response = await api.post(SAVE_RECORDS_URL, recordBase)
return await response.json() return await response.json()
@ -35,8 +45,16 @@
export async function fetchDataForView(viewName, { appname, instanceId }) { export async function fetchDataForView(viewName, { appname, instanceId }) {
const FETCH_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/listRecords/${viewName}`; const FETCH_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/listRecords/${viewName}`;
// TODO: Error handling
const response = await api.get(FETCH_RECORDS_URL); const response = await api.get(FETCH_RECORDS_URL);
return await response.json(); return await response.json();
} }
function overwritePresentProperties(baseObj, overwrites) {
const base = { ...baseObj }
for (let key in base) {
if (overwrites[key]) base[key] = overwrites[key]
}
return base;
}

View File

@ -14,8 +14,8 @@
let selectedModel let selectedModel
$: currentAppInfo = { $: currentAppInfo = {
instanceId: $store.currentInstanceId,
appname: $store.appname, appname: $store.appname,
instanceId: $backendUiStore.selectedDatabase.id
} }
$: recordFields = record ? Object.keys(record) : [] $: recordFields = record ? Object.keys(record) : []
$: models = $store.hierarchy.children $: models = $store.hierarchy.children
@ -66,7 +66,6 @@
<div class="actions"> <div class="actions">
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton <ActionButton
disabled={false}
on:click={async () => { on:click={async () => {
const recordResponse = await api.saveRecord(record || selectedModel, currentAppInfo) const recordResponse = await api.saveRecord(record || selectedModel, currentAppInfo)
backendUiStore.update(state => { backendUiStore.update(state => {

View File

@ -7,8 +7,8 @@
export let record export let record
$: currentAppInfo = { $: currentAppInfo = {
instanceId: $store.currentInstanceId,
appname: $store.appname, appname: $store.appname,
instanceId: $backendUiStore.selectedDatabase.id
} }
function onClosed() { function onClosed() {

View File

@ -91,15 +91,15 @@
<heading> <heading>
{#if !editingField} {#if !editingField}
<i class="ri-list-settings-line button--toggled" /> <i class="ri-list-settings-line button--toggled" />
<h4 class="budibase__title--3">Create / Edit Model</h4> <h3 class="budibase__title--3">Create / Edit Model</h3>
{:else} {:else}
<i class="ri-file-list-line button--toggled" /> <i class="ri-file-list-line button--toggled" />
<h4 class="budibase__title--3">Create / Edit Field</h4> <h3 class="budibase__title--3">Create / Edit Field</h3>
{/if} {/if}
</heading> </heading>
{#if !editingField} {#if !editingField}
<h4 class="budibase__label--big">Settings</h4>
<form class="uk-form-stacked"> <form class="uk-form-stacked">
<h3 class="budibase__label--big">Settings</h3>
<Textbox label="Name" bind:text={record.name} on:change={nameChanged} /> <Textbox label="Name" bind:text={record.name} on:change={nameChanged} />
@ -204,7 +204,7 @@
align-items: center; align-items: center;
} }
h4 { h3 {
margin: 0 0 0 10px; margin: 0 0 0 10px;
} }
</style> </style>

View File

@ -6,47 +6,19 @@
import NavItem from "./NavItem.svelte" import NavItem from "./NavItem.svelte"
import getIcon from "../common/icon" import getIcon from "../common/icon"
const defaultNewChildActions = [ function newModel() {
{ if ($store.currentNode) {
label: "New Root Record", store.newChildRecord()
onclick: store.newRootRecord,
},
{
label: "New Root Index",
onclick: store.newRootIndex,
},
]
let newChildActions = defaultNewChildActions
const setActiveNav = name => () => {
store.setActiveNav(name)
}
store.subscribe(db => {
if (!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) {
newChildActions = defaultNewChildActions
} else { } else {
newChildActions = [ store.newRootRecord()
{ }
label: "New Root Record", backendUiStore.actions.modals.show("MODEL")
onclick: store.newRootRecord, }
},
{ function newView() {
label: "New Root Index", store.newRootIndex()
onclick: store.newRootIndex, backendUiStore.actions.modals.show("VIEW")
},
{
label: `New Child Record of ${db.currentNode.name}`,
onclick: store.newChildRecord,
},
{
label: `New Index on ${db.currentNode.name}`,
onclick: store.newChildIndex,
},
]
} }
})
</script> </script>
<div class="items-root"> <div class="items-root">
@ -60,18 +32,12 @@
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<li <li
class="hoverable" class="hoverable"
on:click={() => { on:click={newModel}>
store.newRootRecord()
backendUiStore.actions.modals.show('MODEL')
}}>
Model Model
</li> </li>
<li <li
class="hoverable" class="hoverable"
on:click={() => { on:click={newView}>
store.newRootIndex()
backendUiStore.actions.modals.show('VIEW')
}}>
View View
</li> </li>
</ul> </ul>