Browse Source

adding, deleting and editing records working

master
Martin McKeaveney 7 years ago
parent
commit
a8fec53ff3
  1. 1
      packages/builder/rollup.config.js
  2. 16
      packages/builder/src/BackendRoot.svelte
  3. 4
      packages/builder/src/builderStore/index.js
  4. 170
      packages/builder/src/builderStore/store/backend.js
  5. 96
      packages/builder/src/builderStore/store/index.js
  6. 26
      packages/builder/src/common/Modal.svelte
  7. 14
      packages/builder/src/database/ActionsHeader.svelte
  8. 58
      packages/builder/src/database/DatabaseRoot.svelte
  9. 42
      packages/builder/src/database/HierarchyRow.svelte
  10. 34
      packages/builder/src/database/ModelDataTable/ModelDataTable.svelte
  11. 6
      packages/builder/src/database/ModelDataTable/TablePagination.svelte
  12. 25
      packages/builder/src/database/ModelDataTable/api.js
  13. 17
      packages/builder/src/database/ModelDataTable/modals/CreateDatabase.svelte
  14. 2
      packages/builder/src/database/ModelDataTable/modals/CreateEditField.svelte
  15. 21
      packages/builder/src/database/ModelDataTable/modals/CreateEditModel.svelte
  16. 19
      packages/builder/src/database/ModelDataTable/modals/CreateEditRecord.svelte
  17. 22
      packages/builder/src/database/ModelDataTable/modals/CreateEditView.svelte
  18. 16
      packages/builder/src/database/ModelDataTable/modals/DeleteRecord.svelte
  19. 4
      packages/builder/src/database/ModelDataTable/modals/index.js
  20. 30
      packages/builder/src/database/ModelView.svelte
  21. 60
      packages/builder/src/nav/BackendNav.svelte
  22. 20
      packages/builder/src/nav/DatabasesList.svelte
  23. 32
      packages/builder/src/nav/HierarchyRow.svelte
  24. 10
      packages/builder/src/nav/NavItem.svelte
  25. 46
      packages/builder/src/nav/SchemaManagementDrawer.svelte
  26. 7
      packages/server/middleware/routers.js

1
packages/builder/rollup.config.js

@ -103,6 +103,7 @@ const lodash_fp_exports = [
"toNumber", "toNumber",
"takeRight", "takeRight",
"toPairs", "toPairs",
"remove"
] ]
const lodash_exports = [ const lodash_exports = [

16
packages/builder/src/BackendRoot.svelte

@ -7,10 +7,7 @@
import AccessLevels from "./accessLevels/AccessLevelsRoot.svelte" import AccessLevels from "./accessLevels/AccessLevelsRoot.svelte"
import ComingSoon from "./common/ComingSoon.svelte" import ComingSoon from "./common/ComingSoon.svelte"
import { store } from "./builderStore" import { store, backendUiStore } from "./builderStore"
import { setContext } from "svelte"
let activeNav = "database"
</script> </script>
<div class="root"> <div class="root">
@ -18,13 +15,14 @@
<BackendNav /> <BackendNav />
</div> </div>
<div class="content"> <div class="content">
<Database /> {#if $backendUiStore.leftNavItem === 'DATABASE'}
</div> <Database />
<!-- {:else if activeNav === 'actions'} {:else if $backendUiStore.leftNavItem === 'ACTIONS'}
<ActionsAndTriggers /> <ActionsAndTriggers />
{:else if activeNav === 'access levels'} {:else if $backendUiStore.leftNavItem === 'ACCESS_LEVELS'}
<AccessLevels /> <AccessLevels />
{/if} --> {/if}
</div>
<div class="nav"> <div class="nav">
<SchemaManagementDrawer /> <SchemaManagementDrawer />
</div> </div>

4
packages/builder/src/builderStore/index.js

@ -1,7 +1,9 @@
import getStore from "./store" import { getStore } from "./store"
import { getBackendUiStore } from "./store/backend"
import LogRocket from "logrocket"; import LogRocket from "logrocket";
export const store = getStore() export const store = getStore()
export const backendUiStore = getBackendUiStore()
export const initialise = async () => { export const initialise = async () => {
try { try {

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

@ -1,9 +1,12 @@
import { writable } from "svelte/store";
import api from "../api" import api from "../api"
import { import {
filter, filter,
cloneDeep, cloneDeep,
sortBy, sortBy,
find map,
find,
remove
} from "lodash/fp" } from "lodash/fp"
import { hierarchy as hierarchyFunctions } from "../../../../core/src" import { hierarchy as hierarchyFunctions } from "../../../../core/src"
import { import {
@ -13,10 +16,47 @@ import {
constructHierarchy, constructHierarchy,
templateApi, templateApi,
} from "../../common/core" } from "../../common/core"
import { store } from "../index";
export const createShadowHierarchy = hierarchy => export const getBackendUiStore = () => {
constructHierarchy(JSON.parse(JSON.stringify(hierarchy))) const INITIAL_BACKEND_UI_STATE = {
leftNavItem: "DATABASE",
selectedView: {
records: [],
name: ""
},
selectedRecord: {},
selectedDatabase: {},
selectedModel: {},
}
const store = writable(INITIAL_BACKEND_UI_STATE)
store.actions = {
navigate: name => store.update(state => ({ ...state, leftNavItem: name })),
database: {
select: db => store.update(state => ({ ...state, selectedDatabase: db })),
},
records: {
delete: record => store.update(state => {
state.selectedView.records = remove(state.selectedView.records, { key: record.key });
return state
}),
},
modals: {
show: modal => store.update(state => ({ ...state, visibleModal: modal })),
hide: () => store.update(state => ({ ...state, visibleModal: null }))
}
}
return store
};
// Store Actions
export const createShadowHierarchy = hierarchy => {
const hi = constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))
console.log(hi)
return hi
}
export const saveBackend = async state => { export const saveBackend = async state => {
await api.post(`/_builder/api/${state.appname}/backend`, { await api.post(`/_builder/api/${state.appname}/backend`, {
@ -30,58 +70,57 @@ export const saveBackend = async state => {
} }
export const newRecord = (store, useRoot) => () => { export const newRecord = (store, useRoot) => () => {
store.update(s => { store.update(state => {
s.currentNodeIsNew = true state.currentNodeIsNew = true
const shadowHierarchy = createShadowHierarchy(s.hierarchy) const shadowHierarchy = createShadowHierarchy(state.hierarchy)
const parent = useRoot const parent = useRoot
? shadowHierarchy ? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId) : getNode(shadowHierarchy, state.currentNode.nodeId)
s.errors = [] state.errors = []
s.currentNode = templateApi(shadowHierarchy).getNewRecordTemplate( state.currentNode = templateApi(shadowHierarchy).getNewRecordTemplate(
parent, parent,
"", "",
true true
) )
return s return state
}) })
} }
export const selectExistingNode = store => nodeId => { export const selectExistingNode = store => nodeId => {
store.update(s => { store.update(state => {
const shadowHierarchy = createShadowHierarchy(s.hierarchy) const shadowHierarchy = createShadowHierarchy(state.hierarchy)
s.currentNode = getNode(shadowHierarchy, nodeId) state.currentNode = getNode(shadowHierarchy, nodeId)
s.currentNodeIsNew = false state.currentNodeIsNew = false
s.errors = [] state.errors = []
return s return state
}) })
} }
export const newIndex = (store, useRoot) => () => { export const newIndex = (store, useRoot) => () => {
store.update(s => { store.update(state => {
s.currentNodeIsNew = true state.currentNodeIsNew = true
s.errors = [] state.errors = []
const shadowHierarchy = createShadowHierarchy(s.hierarchy) const shadowHierarchy = createShadowHierarchy(state.hierarchy)
const parent = useRoot const parent = useRoot
? shadowHierarchy ? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId) : getNode(shadowHierarchy, state.currentNode.nodeId)
s.currentNode = templateApi(shadowHierarchy).getNewIndexTemplate(parent) state.currentNode = templateApi(shadowHierarchy).getNewIndexTemplate(parent)
return s return state
}) })
} }
// TODO: ONLY SEEMS TO BE CALLED BY THE BACKEND
export const saveCurrentNode = store => () => { export const saveCurrentNode = store => () => {
store.update(s => { store.update(state => {
const errors = validate.node(s.currentNode) const errors = validate.node(state.currentNode)
s.errors = errors state.errors = errors
if (errors.length > 0) { if (errorstate.length > 0) {
return s return state
} }
const parentNode = getNode(s.hierarchy, s.currentNode.parent().nodeId) const parentNode = getNode(state.hierarchy, state.currentNode.parent().nodeId)
const existingNode = getNode(s.hierarchy, s.currentNode.nodeId) const existingNode = getNode(state.hierarchy, state.currentNode.nodeId)
let index = parentNode.children.length let index = parentNode.children.length
if (existingNode) { if (existingNode) {
@ -93,8 +132,8 @@ export const saveCurrentNode = store => () => {
} }
// should add node into existing hierarchy // should add node into existing hierarchy
const cloned = cloneDeep(s.currentNode) const cloned = cloneDeep(state.currentNode)
templateApi(s.hierarchy).constructNode(parentNode, cloned) templateApi(state.hierarchy).constructNode(parentNode, cloned)
const newIndexOfChild = child => { const newIndexOfChild = child => {
if (child === cloned) return index if (child === cloned) return index
@ -104,29 +143,29 @@ export const saveCurrentNode = store => () => {
parentNode.children = pipe(parentNode.children, [sortBy(newIndexOfChild)]) parentNode.children = pipe(parentNode.children, [sortBy(newIndexOfChild)])
if (!existingNode && s.currentNode.type === "record") { if (!existingNode && state.currentNode.type === "record") {
const defaultIndex = templateApi(s.hierarchy).getNewIndexTemplate( const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
cloned.parent() cloned.parent()
) )
defaultIndex.name = `all_${cloned.collectionName}` defaultIndex.name = `all_${cloned.collectionName}`
defaultIndex.allowedRecordNodeIds = [cloned.nodeId] defaultIndex.allowedRecordNodeIds = [cloned.nodeId]
} }
s.currentNodeIsNew = false state.currentNodeIsNew = false
saveBackend(s) saveBackend(state)
return s return state
}) })
} }
export const deleteCurrentNode = store => () => { export const deleteCurrentNode = store => () => {
store.update(s => { store.update(state => {
const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId) const nodeToDelete = getNode(state.hierarchy, state.currentNode.nodeId)
s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent()) state.currentNode = hierarchyFunctionstate.isRoot(nodeToDelete.parent())
? find(n => n != s.currentNode)(s.hierarchy.children) ? find(n => n != state.currentNode)(state.hierarchy.children)
: nodeToDelete.parent() : nodeToDelete.parent()
if (hierarchyFunctions.isRecord(nodeToDelete)) { if (hierarchyFunctionstate.isRecord(nodeToDelete)) {
nodeToDelete.parent().children = filter( nodeToDelete.parent().children = filter(
c => c.nodeId !== nodeToDelete.nodeId c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().children) )(nodeToDelete.parent().children)
@ -135,9 +174,9 @@ export const deleteCurrentNode = store => () => {
c => c.nodeId !== nodeToDelete.nodeId c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().indexes) )(nodeToDelete.parent().indexes)
} }
s.errors = [] state.errors = []
saveBackend(s) saveBackend(state)
return s return state
}) })
} }
@ -160,4 +199,41 @@ export const deleteField = databaseStore => field => {
return db return db
}) })
}
const incrementAccessLevelsVersion = state =>
(state.accessLevelstate.version = (state.accessLevelstate.version || 0) + 1)
export const saveLevel = store => (newLevel, isNew, oldLevel = null) => {
store.update(state => {
const levels = state.accessLevelstate.levels
const existingLevel = isNew
? null
: find(a => a.name === oldLevel.name)(levels)
if (existingLevel) {
state.accessLevelstate.levels = pipe(levels, [
map(a => (a === existingLevel ? newLevel : a)),
])
} else {
state.accessLevelstate.levelstate.push(newLevel)
}
incrementAccessLevelsVersion(s)
saveBackend(state)
return state
})
}
export const deleteLevel = store => level => {
store.update(state => {
state.accessLevelstate.levels = filter(t => t.name !== level.name)(
state.accessLevelstate.levels
)
incrementAccessLevelsVersion(s)
saveBackend(state)
return state
})
} }

96
packages/builder/src/builderStore/store/index.js

@ -65,61 +65,6 @@ export const getStore = () => {
const store = writable(initial) const store = writable(initial)
// store.api = {
// appDefinition: {
// create: () => {},
// },
// records: {
// create: () => {},
// update: () => {},
// delete: () => {},
// },
// indexes: {
// create: () => {},
// update: () => {},
// delete: () => {},
// },
// pages: {
// create: () => {},
// update: () => {},
// delete: () => {},
// },
// screens: {
// create: () => {},
// select: () => {},
// rename: () => {}
// },
// accessLevels: {
// create: () => {},
// update: () => {},
// delete: () => {},
// },
// users: {
// create: () => {},
// update: () => {},
// delete: () => {},
// },
// actions: {
// update: () => {},
// delete: () => {}
// },
// triggers: {
// create: () => {},
// update: () => {},
// delete: () => {},
// },
// stylesheets: {
// create: () => {},
// update: () => {},
// delete: () => {},
// },
// components: {
// create: () => {},
// update: () => {},
// delete: () => {},
// }
// }
store.initialise = initialise(store, initial) store.initialise = initialise(store, initial)
store.newChildRecord = backendStoreActions.newRecord(store, false) store.newChildRecord = backendStoreActions.newRecord(store, false)
@ -131,14 +76,14 @@ export const getStore = () => {
store.deleteCurrentNode = backendStoreActions.deleteCurrentNode(store) store.deleteCurrentNode = backendStoreActions.deleteCurrentNode(store)
store.saveField = backendStoreActions.saveField(store) store.saveField = backendStoreActions.saveField(store)
store.deleteField = backendStoreActions.deleteField(store) store.deleteField = backendStoreActions.deleteField(store)
store.saveLevel = backendStoreActions.saveLevel(store)
store.deleteLevel = backendStoreActions.deleteLevel(store)
store.importAppDefinition = importAppDefinition(store) store.importAppDefinition = importAppDefinition(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)
store.deleteTrigger = deleteTrigger(store) store.deleteTrigger = deleteTrigger(store)
store.saveLevel = saveLevel(store)
store.deleteLevel = deleteLevel(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)
@ -319,43 +264,6 @@ const deleteTrigger = store => trigger => {
}) })
} }
const incrementAccessLevelsVersion = s =>
(s.accessLevels.version = (s.accessLevels.version || 0) + 1)
const saveLevel = store => (newLevel, isNew, oldLevel = null) => {
store.update(s => {
const levels = s.accessLevels.levels
const existingLevel = isNew
? null
: find(a => a.name === oldLevel.name)(levels)
if (existingLevel) {
s.accessLevels.levels = pipe(levels, [
map(a => (a === existingLevel ? newLevel : a)),
])
} else {
s.accessLevels.levels.push(newLevel)
}
incrementAccessLevelsVersion(s)
saveBackend(s)
return s
})
}
const deleteLevel = store => level => {
store.update(s => {
s.accessLevels.levels = filter(t => t.name !== level.name)(
s.accessLevels.levels
)
incrementAccessLevelsVersion(s)
saveBackend(s)
return s
})
}
const createShadowHierarchy = hierarchy => const createShadowHierarchy = hierarchy =>
constructHierarchy(JSON.parse(JSON.stringify(hierarchy))) constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))

26
packages/builder/src/common/Modal.svelte

@ -3,7 +3,7 @@
import ActionButton from "../common/ActionButton.svelte" import ActionButton from "../common/ActionButton.svelte"
export let isOpen = false export let isOpen = false
export let onClosed = () => {} export let onClosed
export let id = "" export let id = ""
export let title export let title
@ -27,19 +27,21 @@
</script> </script>
<div bind:this={ukModal} uk-modal {id}> <div bind:this={ukModal} uk-modal {id}>
<div class="uk-modal-dialog" uk-overflow-auto> {#if isOpen}
{#if title} <div class="uk-modal-dialog" uk-overflow-auto>
<div class="uk-modal-header"> {#if title}
<h4 class="budibase__title--4">{title}</h4> <div class="uk-modal-header">
</div> <h4 class="budibase__title--4">{title}</h4>
{/if} </div>
<div class="uk-modal-body">
{#if onClosed}
<button class="uk-modal-close-default" type="button" uk-close />
{/if} {/if}
<slot /> <div class="uk-modal-body">
{#if onClosed}
<button class="uk-modal-close-default" type="button" uk-close />
{/if}
<slot />
</div>
</div> </div>
</div> {/if}
</div> </div>
<style> <style>

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

@ -6,20 +6,12 @@
import Modal from "../common/Modal.svelte" import Modal from "../common/Modal.svelte"
import ErrorsBox from "../common/ErrorsBox.svelte" import ErrorsBox from "../common/ErrorsBox.svelte"
export let left
let confirmDelete = false let confirmDelete = false
const openConfirmDelete = () => { const openConfirmDelete = () => {
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()
@ -39,10 +31,8 @@
{/if} {/if}
</ButtonGroup> </ButtonGroup>
{#if !!$store.errors && $store.errors.length > 0} {#if $store.errors && $store.errors.length > 0}
<div style="width: 500px"> <ErrorsBox errors={$store.errors} />
<ErrorsBox errors={$store.errors} />
</div>
{/if} {/if}
<Modal onClosed={() => (confirmDelete = false)} bind:isOpen={confirmDelete}> <Modal onClosed={() => (confirmDelete = false)} bind:isOpen={confirmDelete}>

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

@ -1,10 +1,9 @@
<script> <script>
import HierarchyRow from "./HierarchyRow.svelte"
import ModelView from "./ModelView.svelte" import ModelView from "./ModelView.svelte"
import IndexView from "./IndexView.svelte" import IndexView from "./IndexView.svelte"
import ModelDataTable from "./ModelDataTable" import ModelDataTable from "./ModelDataTable"
import ActionsHeader from "./ActionsHeader.svelte" import ActionsHeader from "./ActionsHeader.svelte"
import { store } from "../builderStore" import { store, backendUiStore } 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 ActionButton from "../common/ActionButton.svelte"
@ -13,35 +12,53 @@
CreateEditRecordModal, CreateEditRecordModal,
CreateEditModelModal, CreateEditModelModal,
CreateEditViewModal, CreateEditViewModal,
CreateDatabaseModal
} from "./ModelDataTable/modals" } from "./ModelDataTable/modals"
let modalOpen
let selectedRecord let selectedRecord
function selectRecord(record) { function selectRecord(record) {
selectedRecord = record selectedRecord = record
modalOpen = true backendUiStore.actions.modals.show("RECORD")
} }
$: recordOpen = $store.currentNode && $store.currentNode.type === 'record' function onClosed() {
$: viewOpen = $store.currentNode && $store.currentNode.type === 'index' // backendUiStore.actions.modals.hide()
}
$: recordOpen = $backendUiStore.visibleModal === "RECORD"
$: modelOpen = $backendUiStore.visibleModal === "MODEL"
$: viewOpen = $backendUiStore.visibleModal === "VIEW"
$: databaseOpen = $backendUiStore.visibleModal === "DATABASE"
// $: recordOpen = $store.currentNode && $store.currentNode.type === 'record'
// $: viewOpen = $store.currentNode && $store.currentNode.type === 'index'
</script> </script>
<CreateEditRecordModal bind:modalOpen record={selectedRecord} /> ({ console.log($backendUiStore.visibleModal) })
<CreateEditModelModal modalOpen={recordOpen} />
<CreateEditViewModal modalOpen={viewOpen} /> <CreateEditRecordModal modalOpen={recordOpen} record={selectedRecord} {onClosed} />
<CreateEditModelModal modalOpen={modelOpen} {onClosed} />
<CreateEditViewModal modalOpen={viewOpen} {onClosed} />
<CreateDatabaseModal modalOpen={databaseOpen} {onClosed} />
<div class="root"> <div class="root">
<div class="node-view"> <div class="node-view">
<div class="breadcrumbs">{$store.currentlySelectedDatabase}</div> <div class="database-actions">
<ActionButton <div class="budibase__label--big">
primary {#if $backendUiStore.selectedDatabase.name}
on:click={() => { {$backendUiStore.selectedDatabase.name} / {$store.currentNode}
selectedRecord = null {/if}
modalOpen = true </div>
}}> <ActionButton
Create new record primary
</ActionButton> on:click={() => {
selectedRecord = null
backendUiStore.actions.modals.show("RECORD")
}}>
Create new record
</ActionButton>
</div>
<ModelDataTable {selectRecord} /> <ModelDataTable {selectRecord} />
</div> </div>
</div> </div>
@ -56,4 +73,9 @@
overflow-y: auto; overflow-y: auto;
flex: 1 1 auto; flex: 1 1 auto;
} }
.database-actions {
display: flex;
justify-content: space-between;
}
</style> </style>

42
packages/builder/src/database/HierarchyRow.svelte

@ -1,42 +0,0 @@
<script>
import { store } from "../builderStore"
import { cloneDeep } from "lodash/fp"
export let level = 0
export let node
</script>
<div class="root">
<div
class="title"
on:click={() => store.selectExistingNode(node.nodeId)}
style="padding-left: {20 + level * 20}px">
{node.name}
</div>
{#if node.children}
{#each node.children as child}
<svelte:self node={child} level={level + 1} />
{/each}
{/if}
</div>
<style>
.root {
display: block;
font-size: 0.9rem;
width: 100%;
cursor: pointer;
font-weight: bold;
}
.title {
font: var(--fontblack);
padding-top: 10px;
padding-right: 5px;
padding-bottom: 10px;
color: var(--secondary100);
}
.title:hover {
background-color: var(--secondary10);
}
</style>

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

@ -1,6 +1,6 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { store } from "../../builderStore" import { store, backendUiStore } from "../../builderStore"
import Select from "../../common/Select.svelte" import Select from "../../common/Select.svelte"
import { getIndexSchema } from "../../common/core" import { getIndexSchema } from "../../common/core"
import ActionButton from "../../common/ActionButton.svelte" import ActionButton from "../../common/ActionButton.svelte"
@ -13,8 +13,6 @@
let pages = [1, 2, 3] let pages = [1, 2, 3]
let selectedView = "" let selectedView = ""
let modalOpen = false let modalOpen = false
let deleteRecordModal = false
let data = []
let headers = [] let headers = []
let selectedRecord let selectedRecord
@ -23,13 +21,20 @@
appname: $store.appname, appname: $store.appname,
instanceId: $store.currentInstanceId instanceId: $store.currentInstanceId
} }
$: data = $backendUiStore.selectedView.records
$: deleteRecordModal = $backendUiStore.visibleModal === "DELETE_RECORD"
const getSchema = getIndexSchema($store.hierarchy) const getSchema = getIndexSchema($store.hierarchy)
async function fetchRecordsForView(viewName) { async function fetchRecordsForView(viewName) {
const recordsForIndex = await api.fetchDataForView(viewName, currentAppInfo) const recordsForIndex = await api.fetchDataForView(viewName, currentAppInfo)
data = recordsForIndex backendUiStore.update(state => {
headers = Object.keys(data[0]) state.selectedView.records = recordsForIndex
if (state.selectedView.records.length > 0) {
headers = Object.keys(recordsForIndex[0])
}
return state
})
} }
onMount(async () => { onMount(async () => {
@ -37,7 +42,10 @@
}) })
</script> </script>
<DeleteRecordModal modalOpen={deleteRecordModal} record={selectedRecord} /> <DeleteRecordModal
modalOpen={deleteRecordModal}
record={selectedRecord}
/>
<section> <section>
<div class="table-controls"> <div class="table-controls">
@ -46,7 +54,6 @@
icon="ri-eye-line" icon="ri-eye-line"
on:change={e => fetchRecordsForView(e.target.value)}> on:change={e => fetchRecordsForView(e.target.value)}>
{#each views as view} {#each views as view}
<!-- ({console.log(getSchema(view))}) ({console.log(view)}) -->
<option value={view.name}>{view.name}</option> <option value={view.name}>{view.name}</option>
{/each} {/each}
</Select> </Select>
@ -62,7 +69,7 @@
</thead> </thead>
<tbody> <tbody>
{#each data as row} {#each data as row}
<tr> <tr class="hoverable">
<td> <td>
<div class="uk-inline"> <div class="uk-inline">
<i class="ri-more-line" /> <i class="ri-more-line" />
@ -78,8 +85,8 @@
<li> <li>
<div <div
on:click={() => { on:click={() => {
deleteRecordModal = true
selectedRecord = row selectedRecord = row
backendUiStore.actions.modals.show("DELETE_RECORD")
}}> }}>
Delete Delete
</div> </div>
@ -98,7 +105,7 @@
{/each} {/each}
</tbody> </tbody>
</table> </table>
<TablePagination {data} /> <TablePagination />
</section> </section>
<style> <style>
@ -118,8 +125,13 @@
font-weight: 500; font-weight: 500;
} }
tr { tbody tr {
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
transition: 0.3s background-color;
}
tbody tr:hover {
background: #fafafa;
} }
.table-controls { .table-controls {

6
packages/builder/src/database/ModelDataTable/TablePagination.svelte

@ -1,5 +1,7 @@
<script> <script>
export let data = [] import { backendUiStore } from "../../builderStore"
$: data = $backendUiStore.selectedView.records
</script> </script>
<div class="pagination"> <div class="pagination">
@ -41,4 +43,4 @@
.ri-more-line:hover { .ri-more-line:hover {
cursor: pointer; cursor: pointer;
} }
</style> </style>

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

@ -2,18 +2,27 @@
import { getNewRecord } from "../../common/core" import { getNewRecord } from "../../common/core"
export async function deleteRecord(record, { appname, instanceId }) { export async function deleteRecord(record, { appname, instanceId }) {
const DELETE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record/${record.name}/${record.id}` const DELETE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record${record.key}`
const response = await api.delete({ const response = await api.delete(DELETE_RECORDS_URL);
url: DELETE_RECORDS_URL
});
return response; return response;
} }
export async function saveRecord(record, { appname, instanceId }) { export async function saveRecord(record, { appname, instanceId }) {
const SAVE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record` let recordBase = { ...record }
const updatedRecord = getNewRecord(record, "")
const response = await api.post(SAVE_RECORDS_URL, updatedRecord) // brand new record
return response if (record.collectionName) {
const collectionKey = `/${record.collectionName}`
recordBase = getNewRecord(recordBase, collectionKey)
// overwrite the new record template values
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 fetchDataForView(viewName, { appname, instanceId }) { export async function fetchDataForView(viewName, { appname, instanceId }) {

17
packages/builder/src/database/ModelDataTable/modals/CreateDatabase.svelte

@ -0,0 +1,17 @@
<script>
import Modal from "../../../common/Modal.svelte"
import ActionButton from "../../../common/ActionButton.svelte"
import * as api from "../api"
export let modalOpen = false
const onClosed = () => (modalOpen = false)
</script>
<Modal {onClosed} isOpen={modalOpen}>
CREATE A NEW DATABASE FROM HERE
<div class="actions">
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton disabled={false}>Save</ActionButton>
</div>
</Modal>

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

@ -10,7 +10,7 @@
const onClosed = () => (modalOpen = false) const onClosed = () => (modalOpen = false)
</script> </script>
<Modal {onClosed} bind:isOpen={modalOpen} title={"Create / Edit Field"}> <Modal {onClosed} isOpen={modalOpen}>
<div class="actions"> <div class="actions">
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <ActionButton alert on:click={onClosed}>Cancel</ActionButton>

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

@ -1,27 +1,22 @@
<script> <script>
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 { backendUiStore } from "../../../builderStore"
import ModelView from "../../ModelView.svelte" import ModelView from "../../ModelView.svelte"
import ActionsHeader from "../../ActionsHeader.svelte" import ActionsHeader from "../../ActionsHeader.svelte"
import * as api from "./api" import * as api from "../api"
export let modalOpen = false export let modalOpen = false
export let onClosed
let recordInfo = {}
const onClosed = () => (modalOpen = false)
</script> </script>
<Modal {onClosed} bind:isOpen={modalOpen} title={'Record'}> <Modal {onClosed} isOpen={modalOpen}>
<h4 class="budibase__title--4">Create / Edit Model</h4> <h4 class="budibase__title--4">
<i class="ri-list-settings-line" />
Create / Edit Model
</h4>
<div class="actions"> <div class="actions">
<ModelView /> <ModelView />
<ActionsHeader /> <ActionsHeader />
<!-- <ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton
disabled={false}
on:click={() => api.createNewRecord(recordInfo)}>
Save
</ActionButton> -->
</div> </div>
</Modal> </Modal>

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

@ -1,13 +1,15 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { store } from "../../../builderStore" import { store, backendUiStore } 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 Select from "../../../common/Select.svelte"
import { getNewRecord } from "../../../common/core"
import * as api from "../api" import * as api from "../api"
export let modalOpen = false export let modalOpen = false
export let record export let record
export let onClosed
let selectedModel let selectedModel
@ -20,16 +22,12 @@
$: modelFields = selectedModel $: modelFields = selectedModel
? selectedModel.fields.map(({ name }) => name) ? selectedModel.fields.map(({ name }) => name)
: [] : []
const onClosed = () => (modalOpen = false)
</script> </script>
<Modal {onClosed} isOpen={modalOpen}> <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">
{console.log('record', record)}
{console.log('selectedModel', selectedModel)}
{console.log('recordFields', recordFields)}
<form class="uk-form-stacked"> <form class="uk-form-stacked">
{#if !record} {#if !record}
<div class="uk-margin"> <div class="uk-margin">
@ -70,7 +68,14 @@
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton <ActionButton
disabled={false} disabled={false}
on:click={() => api.saveRecord(record || selectedModel, currentAppInfo)}> on:click={async () => {
const recordResponse = await api.saveRecord(record || selectedModel, currentAppInfo)
backendUiStore.update(state => {
state.selectedView.records.push(recordResponse)
return state
})
onClosed()
}}>
Save Save
</ActionButton> </ActionButton>
</div> </div>

22
packages/builder/src/database/ModelDataTable/modals/CreateEditView.svelte

@ -1,23 +1,25 @@
<script> <script>
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 * as api from "./api" import IndexView from "../../IndexView.svelte"
import ActionsHeader from "../../ActionsHeader.svelte"
import * as api from "../api"
export let modalOpen = false export let modalOpen = false
export let onClosed
let recordInfo = {} let recordInfo = {}
const onClosed = () => (modalOpen = false)
</script> </script>
<Modal {onClosed} bind:isOpen={modalOpen} title={'Record'}> <Modal {onClosed} isOpen={modalOpen}>
<IndexView />
<ActionsHeader />
<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={() => api.saveRecord(recordInfo)}>
disabled={false}
on:click={() => api.createNewRecord(recordInfo)}>
Save Save
</ActionButton> </ActionButton>
</div> </div> -->
</Modal> </Modal>

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

@ -1,15 +1,24 @@
<script> <script>
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 { store, backendUiStore } from "../../../builderStore"
import * as api from "../api" import * as api from "../api"
export let modalOpen = false export let modalOpen = false
export let record export let record
const onClosed = () => (modalOpen = false) $: currentAppInfo = {
instanceId: $store.currentInstanceId,
appname: $store.appname,
}
function onClosed() {
backendUiStore.actions.modals.hide()
}
</script> </script>
<Modal {onClosed} bind:isOpen={modalOpen}> <Modal {onClosed} 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">
@ -17,7 +26,8 @@
<ActionButton <ActionButton
alert alert
on:click={async () => { on:click={async () => {
await api.deleteRecord(record) await api.deleteRecord(record, currentAppInfo)
backendUiStore.actions.records.delete(record)
onClosed(); onClosed();
}}> }}>
Delete Delete

4
packages/builder/src/database/ModelDataTable/modals/index.js

@ -1,3 +1,5 @@
export { default as DeleteRecordModal } from "./DeleteRecord.svelte"; export { default as DeleteRecordModal } from "./DeleteRecord.svelte";
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"; export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte";
export { default as CreateEditModelModal } from "./CreateEditModel.svelte"; export { default as CreateEditModelModal } from "./CreateEditModel.svelte";
export { default as CreateEditViewModal } from "./CreateEditView.svelte";
export { default as CreateDatabaseModal } from "./CreateDatabase.svelte";

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

@ -1,6 +1,7 @@
<script> <script>
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 Select from "../common/Select.svelte"
import getIcon from "../common/icon" import getIcon from "../common/icon"
import FieldView from "./FieldView.svelte" import FieldView from "./FieldView.svelte"
import Modal from "../common/Modal.svelte" import Modal from "../common/Modal.svelte"
@ -19,6 +20,9 @@
let deleteField let deleteField
let onFinishedFieldEdit let onFinishedFieldEdit
let editIndex let editIndex
let parentRecord
$: models = $store.hierarchy.children
store.subscribe($store => { store.subscribe($store => {
record = $store.currentNode record = $store.currentNode
@ -98,16 +102,20 @@
</script> </script>
<div class="root"> <div class="root">
<form class="uk-form-stacked"> <form class="uk-form-stacked">
<h3 class="budibase__title--3">
<i class="ri-list-settings-line" />
Create / Edit Model
</h3>
<h3 class="budibase__label--big">Settings</h3> <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} />
<label class="uk-form-label">Parent</label>
<div class="uk-form-controls">
<Select
value={parentRecord}
on:change={e => (parentRecord = e.target.value)}>
{#each models as model}
<option value={model}>{model.name}</option>
{/each}
</Select>
</div>
{#if !record.isSingle} {#if !record.isSingle}
<Textbox label="Collection Name" bind:text={record.collectionName} /> <Textbox label="Collection Name" bind:text={record.collectionName} />
<Textbox <Textbox
@ -121,12 +129,6 @@
<span class="budibase__label--big">Fields</span> <span class="budibase__label--big">Fields</span>
<h4 class="hoverable" on:click={newField}>Add new field</h4> <h4 class="hoverable" on:click={newField}>Add new field</h4>
</div> </div>
<!-- <h3 class="budibase__label--big">
Fields
<span class="add-field-button" on:click={newField}>
{@html getIcon('plus')}
</span>
</h3> -->
<table class="fields-table uk-table budibase__table"> <table class="fields-table uk-table budibase__table">
<thead> <thead>
@ -139,7 +141,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each record ? 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)} />
@ -148,7 +150,7 @@
<div>{field.name}</div> <div>{field.name}</div>
</td> </td>
<td>{field.type}</td> <td>{field.type}</td>
<td>({console.log(field.typeOptions)}) {field.typeOptions.values}</td> <td>{field.typeOptions.values}</td>
<td> <td>
<span class="edit-button" on:click={() => deleteField(field)}> <span class="edit-button" on:click={() => deleteField(field)}>
{@html getIcon('trash')} {@html getIcon('trash')}

60
packages/builder/src/nav/BackendNav.svelte

@ -1,6 +1,6 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { store } from "../builderStore" import { store, backendUiStore } from "../builderStore"
import HierarchyRow from "./HierarchyRow.svelte" import HierarchyRow from "./HierarchyRow.svelte"
import DatabasesList from "./DatabasesList.svelte" import DatabasesList from "./DatabasesList.svelte"
import UsersList from "./UsersList.svelte" import UsersList from "./UsersList.svelte"
@ -8,59 +8,16 @@
import NavItem from "./NavItem.svelte" import NavItem from "./NavItem.svelte"
import getIcon from "../common/icon" import getIcon from "../common/icon"
// top level store modifiers
const newRootRecord = () => store.newRootRecord()
const newChildIndex = () => store.newChildIndex()
const newRootIndex = () => store.newRootIndex()
const newUser = () => {
store.update(state => {})
}
const newDatabase = () => { const newDatabase = () => {
store.update(state => {}) store.update(state => {})
} }
const userManagementActions = [
{
label: "New User",
onclick: newUser,
},
]
const databaseManagementActions = [ const databaseManagementActions = [
{ {
label: "New Database", label: "New Database",
onclick: newDatabase, onclick: newDatabase,
}, },
] ]
// let newChildActions = defaultNewChildActions
const setActiveNav = name => () => getContext("navigation").setActiveNav(name);
// store.subscribe(db => {
// if (!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) {
// newChildActions = defaultNewChildActions
// } else {
// newChildActions = [
// {
// label: "New Root Record",
// onclick: newRootRecord,
// },
// {
// label: "New Root Index",
// onclick: newRootIndex,
// },
// {
// label: `New Child Record of ${db.currentNode.name}`,
// onclick: newChildRecord,
// },
// {
// label: `New Index on ${db.currentNode.name}`,
// onclick: newChildIndex,
// },
// ]
// }
// })
</script> </script>
<div class="items-root"> <div class="items-root">
@ -68,20 +25,12 @@
<div class="components-list-container"> <div class="components-list-container">
<div class="nav-group-header"> <div class="nav-group-header">
<div class="hierarchy-title">Databases</div> <div class="hierarchy-title">Databases</div>
<i class="ri-add-line" /> <i class="ri-add-line hoverable" on:click={() => backendUiStore.actions.modals.show("DATABASE")} />
</div> </div>
</div> </div>
<div class="hierarchy-items-container"> <div class="hierarchy-items-container">
<DatabasesList /> <DatabasesList />
<!-- {#each $store.hierarchy.children as record}
<HierarchyRow node={record} type="record" />
{/each}
{#each $store.hierarchy.indexes as index}
<HierarchyRow node={index} type="index" />
{/each} -->
</div> </div>
</div> </div>
<hr /> <hr />
@ -95,10 +44,9 @@
<div class="hierarchy-items-container"> <div class="hierarchy-items-container">
<UsersList /> <UsersList />
<!-- {#each $store.hierarchy.children as record}
<HierarchyRow node={record} type="record" />
{/each} -->
</div> </div>
<NavItem name="ACCESS_LEVELS" label="User Levels" />
</div> </div>
</div> </div>

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

@ -1,32 +1,30 @@
<script> <script>
import { store } from "../builderStore" import { store, backendUiStore } from "../builderStore"
import getIcon from "../common/icon" import getIcon from "../common/icon"
import { CheckIcon } from "../common/Icons" import { CheckIcon } from "../common/Icons"
$: instances = $store.appInstances $: instances = $store.appInstances
function selectDatabase(databaseId) { function selectDatabase(database) {
store.update(state => { backendUiStore.actions.database.select(database)
state.currentlySelectedDatabase = databaseId backendUiStore.actions.navigate("DATABASE")
return state
})
} }
</script> </script>
<div class="root"> <div class="root">
<ul> <ul>
{#each $store.appInstances as { id, name }} {#each $store.appInstances as database}
<li> <li>
<span class="icon"> <span class="icon">
{#if id === $store.currentlySelectedDatabase} {#if database.id === $backendUiStore.selectedDatabase.id}
<CheckIcon /> <CheckIcon />
{/if} {/if}
</span> </span>
<button <button
class:active={id === $store.currentlySelectedDatabase} class:active={database.id === $backendUiStore.selectedDatabase.id}
on:click={() => selectDatabase(id)}> on:click={() => selectDatabase(database)}>
{name} {database.name}
</button> </button>
</li> </li>
{/each} {/each}

32
packages/builder/src/nav/HierarchyRow.svelte

@ -1,6 +1,6 @@
<script> <script>
import { getContext } from "svelte"; import { getContext } from "svelte"
import { store } from "../builderStore" import { store, backendUiStore } from "../builderStore"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import getIcon from "../common/icon" import getIcon from "../common/icon"
export let level = 0 export let level = 0
@ -10,8 +10,8 @@
let navActive = "" let navActive = ""
const ICON_MAP = { const ICON_MAP = {
index: "ri-equalizer-line", index: "ri-eye-line",
record: "ri-list-settings-line" record: "ri-list-settings-line",
} }
store.subscribe(state => { store.subscribe(state => {
@ -19,13 +19,19 @@
navActive = node.nodeId === state.currentNode.nodeId navActive = node.nodeId === state.currentNode.nodeId
} }
}) })
function selectHierarchyItem(node) {
store.selectExistingNode(node.nodeId)
const modalType = node.type === "index" ? "VIEW" : "MODEL"
backendUiStore.actions.modals.show(modalType)
}
</script> </script>
<div> <div>
<div <div
on:click={() => store.selectExistingNode(node.nodeId)} on:click={() => selectHierarchyItem(node)}
class="budibase__nav-item hierarchy-item" class="budibase__nav-item hierarchy-item"
class:capitalized={type === "record"} class:capitalized={type === 'record'}
style="padding-left: {20 + level * 20}px" style="padding-left: {20 + level * 20}px"
class:selected={navActive}> class:selected={navActive}>
<i class={ICON_MAP[type]} /> <i class={ICON_MAP[type]} />
@ -44,12 +50,12 @@
</div> </div>
<style> <style>
.hierarchy-item { .hierarchy-item {
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
} }
.capitalized { .capitalized {
text-transform: capitalize; text-transform: capitalize;
} }
</style> </style>

10
packages/builder/src/nav/NavItem.svelte

@ -1,17 +1,13 @@
<script> <script>
import { getContext, setContext } from "svelte";
import getIcon from "../common/icon" import getIcon from "../common/icon"
import { backendUiStore } from "../builderStore";
export let name = "" export let name = ""
export let label = "" export let label = ""
$: navActive = getContext("activeNav") === name $: navActive = $backendUiStore.leftNavItem === name
// store.subscribe(db => { const setActive = () => backendUiStore.actions.navigate(name)
// navActive = db.activeNav === name
// })
const setActive = () => setContext("activeNav", name);
</script> </script>
<div <div

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

@ -1,35 +1,19 @@
<script> <script>
import { store } from "../builderStore" import { store, backendUiStore } from "../builderStore"
import HierarchyRow from "./HierarchyRow.svelte" import HierarchyRow from "./HierarchyRow.svelte"
import DropdownButton from "../common/DropdownButton.svelte" import DropdownButton from "../common/DropdownButton.svelte"
import { hierarchy as hierarchyFunctions } from "../../../core/src" import { hierarchy as hierarchyFunctions } from "../../../core/src"
import NavItem from "./NavItem.svelte" import NavItem from "./NavItem.svelte"
import getIcon from "../common/icon" import getIcon from "../common/icon"
const newRootRecord = () => {
store.newRootRecord()
}
const newRootIndex = () => {
store.newRootIndex()
}
const newChildRecord = () => {
store.newChildRecord()
}
const newChildIndex = () => {
store.newChildIndex()
}
const defaultNewChildActions = [ const defaultNewChildActions = [
{ {
label: "New Root Record", label: "New Root Record",
onclick: newRootRecord, onclick: store.newRootRecord,
}, },
{ {
label: "New Root Index", label: "New Root Index",
onclick: newRootIndex, onclick: store.newRootIndex,
}, },
] ]
@ -46,19 +30,19 @@
newChildActions = [ newChildActions = [
{ {
label: "New Root Record", label: "New Root Record",
onclick: newRootRecord, onclick: store.newRootRecord,
}, },
{ {
label: "New Root Index", label: "New Root Index",
onclick: newRootIndex, onclick: store.newRootIndex,
}, },
{ {
label: `New Child Record of ${db.currentNode.name}`, label: `New Child Record of ${db.currentNode.name}`,
onclick: newChildRecord, onclick: store.newChildRecord,
}, },
{ {
label: `New Index on ${db.currentNode.name}`, label: `New Index on ${db.currentNode.name}`,
onclick: newChildIndex, onclick: store.newChildIndex,
}, },
] ]
} }
@ -72,12 +56,22 @@
<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 hoverable" /> <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 class="hoverable" on:click={newRootRecord}> <li
class="hoverable"
on:click={() => {
store.newRootRecord()
backendUiStore.actions.modals.show('MODEL')
}}>
Model Model
</li> </li>
<li class="hoverable" on:click={newRootIndex}> <li
class="hoverable"
on:click={() => {
store.newRootIndex()
backendUiStore.actions.modals.show('VIEW')
}}>
View View
</li> </li>
</ul> </ul>

7
packages/server/middleware/routers.js

@ -237,6 +237,7 @@ module.exports = (config, app) => {
} else { } else {
ctx.response.status = StatusCodes.UNAUTHORIZED ctx.response.status = StatusCodes.UNAUTHORIZED
} }
next()
}) })
.post("/:appname/api/changeMyPassword", routeHandlers.changeMyPassword) .post("/:appname/api/changeMyPassword", routeHandlers.changeMyPassword)
.post( .post(
@ -319,8 +320,4 @@ module.exports = (config, app) => {
.post("/:appname/api/apphierarchy", routeHandlers.saveAppHierarchy) .post("/:appname/api/apphierarchy", routeHandlers.saveAppHierarchy)
return router return router
} }
/*
front end get authenticateTemporaryAccess {}
*/
Loading…
Cancel
Save