adding, deleting and editing records working

This commit is contained in:
Martin McKeaveney 2020-03-20 18:47:01 +00:00
parent 38d7623862
commit a8fec53ff3
26 changed files with 375 additions and 423 deletions

View File

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

View File

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

View File

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

View File

@ -1,9 +1,12 @@
import { writable } from "svelte/store";
import api from "../api"
import {
filter,
cloneDeep,
sortBy,
find
map,
find,
remove
} from "lodash/fp"
import { hierarchy as hierarchyFunctions } from "../../../../core/src"
import {
@ -13,10 +16,47 @@ import {
constructHierarchy,
templateApi,
} from "../../common/core"
import { store } from "../index";
export const createShadowHierarchy = hierarchy =>
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))
export const getBackendUiStore = () => {
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 => {
await api.post(`/_builder/api/${state.appname}/backend`, {
@ -30,58 +70,57 @@ export const saveBackend = async state => {
}
export const newRecord = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
store.update(state => {
state.currentNodeIsNew = true
const shadowHierarchy = createShadowHierarchy(state.hierarchy)
const parent = useRoot
? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId)
s.errors = []
s.currentNode = templateApi(shadowHierarchy).getNewRecordTemplate(
: getNode(shadowHierarchy, state.currentNode.nodeId)
state.errors = []
state.currentNode = templateApi(shadowHierarchy).getNewRecordTemplate(
parent,
"",
true
)
return s
return state
})
}
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
store.update(state => {
const shadowHierarchy = createShadowHierarchy(state.hierarchy)
state.currentNode = getNode(shadowHierarchy, nodeId)
state.currentNodeIsNew = false
state.errors = []
return state
})
}
export const newIndex = (store, useRoot) => () => {
store.update(s => {
s.currentNodeIsNew = true
s.errors = []
const shadowHierarchy = createShadowHierarchy(s.hierarchy)
store.update(state => {
state.currentNodeIsNew = true
state.errors = []
const shadowHierarchy = createShadowHierarchy(state.hierarchy)
const parent = useRoot
? shadowHierarchy
: getNode(shadowHierarchy, s.currentNode.nodeId)
: getNode(shadowHierarchy, state.currentNode.nodeId)
s.currentNode = templateApi(shadowHierarchy).getNewIndexTemplate(parent)
return s
state.currentNode = templateApi(shadowHierarchy).getNewIndexTemplate(parent)
return state
})
}
// 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
store.update(state => {
const errors = validate.node(state.currentNode)
state.errors = errors
if (errorstate.length > 0) {
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
if (existingNode) {
@ -93,8 +132,8 @@ export const saveCurrentNode = store => () => {
}
// should add node into existing hierarchy
const cloned = cloneDeep(s.currentNode)
templateApi(s.hierarchy).constructNode(parentNode, cloned)
const cloned = cloneDeep(state.currentNode)
templateApi(state.hierarchy).constructNode(parentNode, cloned)
const newIndexOfChild = child => {
if (child === cloned) return index
@ -104,29 +143,29 @@ export const saveCurrentNode = store => () => {
parentNode.children = pipe(parentNode.children, [sortBy(newIndexOfChild)])
if (!existingNode && s.currentNode.type === "record") {
const defaultIndex = templateApi(s.hierarchy).getNewIndexTemplate(
if (!existingNode && state.currentNode.type === "record") {
const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
cloned.parent()
)
defaultIndex.name = `all_${cloned.collectionName}`
defaultIndex.allowedRecordNodeIds = [cloned.nodeId]
}
s.currentNodeIsNew = false
state.currentNodeIsNew = false
saveBackend(s)
saveBackend(state)
return s
return state
})
}
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)
store.update(state => {
const nodeToDelete = getNode(state.hierarchy, state.currentNode.nodeId)
state.currentNode = hierarchyFunctionstate.isRoot(nodeToDelete.parent())
? find(n => n != state.currentNode)(state.hierarchy.children)
: nodeToDelete.parent()
if (hierarchyFunctions.isRecord(nodeToDelete)) {
if (hierarchyFunctionstate.isRecord(nodeToDelete)) {
nodeToDelete.parent().children = filter(
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().children)
@ -135,9 +174,9 @@ export const deleteCurrentNode = store => () => {
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().indexes)
}
s.errors = []
saveBackend(s)
return s
state.errors = []
saveBackend(state)
return state
})
}
@ -161,3 +200,40 @@ export const deleteField = databaseStore => field => {
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
})
}

View File

@ -65,61 +65,6 @@ export const getStore = () => {
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.newChildRecord = backendStoreActions.newRecord(store, false)
@ -131,14 +76,14 @@ export const getStore = () => {
store.deleteCurrentNode = backendStoreActions.deleteCurrentNode(store)
store.saveField = backendStoreActions.saveField(store)
store.deleteField = backendStoreActions.deleteField(store)
store.saveLevel = backendStoreActions.saveLevel(store)
store.deleteLevel = backendStoreActions.deleteLevel(store)
store.importAppDefinition = importAppDefinition(store)
store.saveAction = saveAction(store)
store.deleteAction = deleteAction(store)
store.saveTrigger = saveTrigger(store)
store.deleteTrigger = deleteTrigger(store)
store.saveLevel = saveLevel(store)
store.deleteLevel = deleteLevel(store)
store.saveScreen = saveScreen(store)
store.addComponentLibrary = addComponentLibrary(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 =>
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))

View File

@ -3,7 +3,7 @@
import ActionButton from "../common/ActionButton.svelte"
export let isOpen = false
export let onClosed = () => {}
export let onClosed
export let id = ""
export let title
@ -27,6 +27,7 @@
</script>
<div bind:this={ukModal} uk-modal {id}>
{#if isOpen}
<div class="uk-modal-dialog" uk-overflow-auto>
{#if title}
<div class="uk-modal-header">
@ -40,6 +41,7 @@
<slot />
</div>
</div>
{/if}
</div>
<style>

View File

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

View File

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

View File

@ -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>

View File

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

View File

@ -1,5 +1,7 @@
<script>
export let data = []
import { backendUiStore } from "../../builderStore"
$: data = $backendUiStore.selectedView.records
</script>
<div class="pagination">

View File

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

View File

@ -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>

View File

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

View File

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

View File

@ -1,13 +1,15 @@
<script>
import { onMount } from "svelte"
import { store } from "../../../builderStore"
import { store, backendUiStore } from "../../../builderStore"
import Modal from "../../../common/Modal.svelte"
import ActionButton from "../../../common/ActionButton.svelte"
import Select from "../../../common/Select.svelte"
import { getNewRecord } from "../../../common/core"
import * as api from "../api"
export let modalOpen = false
export let record
export let onClosed
let selectedModel
@ -21,15 +23,11 @@
? selectedModel.fields.map(({ name }) => name)
: []
const onClosed = () => (modalOpen = false)
</script>
<Modal {onClosed} isOpen={modalOpen}>
<h4 class="budibase__title--4">Create / Edit Record</h4>
<div class="actions">
{console.log('record', record)}
{console.log('selectedModel', selectedModel)}
{console.log('recordFields', recordFields)}
<form class="uk-form-stacked">
{#if !record}
<div class="uk-margin">
@ -70,7 +68,14 @@
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton
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
</ActionButton>
</div>

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
<script>
import Textbox from "../common/Textbox.svelte"
import Button from "../common/Button.svelte"
import Select from "../common/Select.svelte"
import getIcon from "../common/icon"
import FieldView from "./FieldView.svelte"
import Modal from "../common/Modal.svelte"
@ -19,6 +20,9 @@
let deleteField
let onFinishedFieldEdit
let editIndex
let parentRecord
$: models = $store.hierarchy.children
store.subscribe($store => {
record = $store.currentNode
@ -98,16 +102,20 @@
</script>
<div class="root">
<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>
<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}
<Textbox label="Collection Name" bind:text={record.collectionName} />
<Textbox
@ -121,12 +129,6 @@
<span class="budibase__label--big">Fields</span>
<h4 class="hoverable" on:click={newField}>Add new field</h4>
</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">
<thead>
@ -148,7 +150,7 @@
<div>{field.name}</div>
</td>
<td>{field.type}</td>
<td>({console.log(field.typeOptions)}) {field.typeOptions.values}</td>
<td>{field.typeOptions.values}</td>
<td>
<span class="edit-button" on:click={() => deleteField(field)}>
{@html getIcon('trash')}

View File

@ -1,6 +1,6 @@
<script>
import { getContext } from "svelte"
import { store } from "../builderStore"
import { store, backendUiStore } from "../builderStore"
import HierarchyRow from "./HierarchyRow.svelte"
import DatabasesList from "./DatabasesList.svelte"
import UsersList from "./UsersList.svelte"
@ -8,59 +8,16 @@
import NavItem from "./NavItem.svelte"
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 = () => {
store.update(state => {})
}
const userManagementActions = [
{
label: "New User",
onclick: newUser,
},
]
const databaseManagementActions = [
{
label: "New Database",
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>
<div class="items-root">
@ -68,20 +25,12 @@
<div class="components-list-container">
<div class="nav-group-header">
<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 class="hierarchy-items-container">
<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>
<hr />
@ -95,10 +44,9 @@
<div class="hierarchy-items-container">
<UsersList />
<!-- {#each $store.hierarchy.children as record}
<HierarchyRow node={record} type="record" />
{/each} -->
</div>
<NavItem name="ACCESS_LEVELS" label="User Levels" />
</div>
</div>

View File

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

View File

@ -1,6 +1,6 @@
<script>
import { getContext } from "svelte";
import { store } from "../builderStore"
import { getContext } from "svelte"
import { store, backendUiStore } from "../builderStore"
import { cloneDeep } from "lodash/fp"
import getIcon from "../common/icon"
export let level = 0
@ -10,8 +10,8 @@
let navActive = ""
const ICON_MAP = {
index: "ri-equalizer-line",
record: "ri-list-settings-line"
index: "ri-eye-line",
record: "ri-list-settings-line",
}
store.subscribe(state => {
@ -19,13 +19,19 @@
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>
<div>
<div
on:click={() => store.selectExistingNode(node.nodeId)}
on:click={() => selectHierarchyItem(node)}
class="budibase__nav-item hierarchy-item"
class:capitalized={type === "record"}
class:capitalized={type === 'record'}
style="padding-left: {20 + level * 20}px"
class:selected={navActive}>
<i class={ICON_MAP[type]} />

View File

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

View File

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

View File

@ -237,6 +237,7 @@ module.exports = (config, app) => {
} else {
ctx.response.status = StatusCodes.UNAUTHORIZED
}
next()
})
.post("/:appname/api/changeMyPassword", routeHandlers.changeMyPassword)
.post(
@ -320,7 +321,3 @@ module.exports = (config, app) => {
return router
}
/*
front end get authenticateTemporaryAccess {}
*/