Merge branch 'new-backend' of github.com:Budibase/budibase into new-backend

This commit is contained in:
Michael Shanks 2020-03-25 08:49:35 +00:00
commit 1cc2991d18
10 changed files with 107 additions and 74 deletions

View File

@ -47,7 +47,6 @@
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"shortid": "^2.2.8", "shortid": "^2.2.8",
"string_decoder": "^1.2.0", "string_decoder": "^1.2.0",
"svelte-routing": "^1.4.2",
"uikit": "^3.1.7" "uikit": "^3.1.7"
}, },
"devDependencies": { "devDependencies": {

View File

@ -105,7 +105,9 @@ const lodash_fp_exports = [
"toPairs", "toPairs",
"remove", "remove",
"findIndex", "findIndex",
"compose" "compose",
"get",
"tap"
] ]
const lodash_exports = [ const lodash_exports = [

View File

@ -4,7 +4,7 @@
import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte" import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte"
import BackendRoot from "./BackendRoot.svelte" import BackendRoot from "./BackendRoot.svelte"
import { fade } from "svelte/transition" import { fade } from "svelte/transition"
import { SettingsIcon, PreviewIcon, HelpIcon } from "./common/Icons/" import { SettingsIcon, PreviewIcon } from "./common/Icons/"
const TABS = { const TABS = {
BACKEND: "backend", BACKEND: "backend",

View File

@ -23,7 +23,6 @@ export const getBackendUiStore = () => {
name: "" name: ""
}, },
breadcrumbs: [], breadcrumbs: [],
selectedRecord: {},
selectedDatabase: {}, selectedDatabase: {},
selectedModel: {}, selectedModel: {},
} }
@ -49,14 +48,15 @@ export const getBackendUiStore = () => {
return state return state
}), }),
}, },
views: {
select: view => store.update(state => {
state.selectedView = { ...state.selectedView, ...view }
return state
})
},
modals: { modals: {
show: modal => store.update(state => ({ ...state, visibleModal: modal })), show: modal => store.update(state => ({ ...state, visibleModal: modal })),
hide: () => store.update(state => ({ ...state, visibleModal: null })) hide: () => store.update(state => ({ ...state, visibleModal: null }))
},
nodes: {
select: () => {},
update: () => {},
delete: () => {},
} }
} }

View File

@ -11,20 +11,11 @@
padding: 10px; padding: 10px;
margin-top: 5px; margin-top: 5px;
margin-bottom: 10px; margin-bottom: 10px;
background: var(--primary100); background: var(--secondary80);
color: var(--white); color: var(--white);
font-family: "Courier New", Courier, monospace; font-family: "Courier New", Courier, monospace;
width: 95%; width: 95%;
height: 100px; height: 100px;
border-radius: 5px; border-radius: 5px;
} }
span {
margin-left: 5px;
}
.header {
display: flex;
align-items: center;
}
</style> </style>

View File

@ -4,11 +4,9 @@
import Button from "../common/Button.svelte" import Button from "../common/Button.svelte"
import Dropdown from "../common/Dropdown.svelte" import Dropdown from "../common/Dropdown.svelte"
import { store } from "../builderStore" import { store } from "../builderStore"
import { filter, some, map } from "lodash/fp" import { filter, some, map, compose } from "lodash/fp"
import { hierarchy as hierarchyFunctions, common } from "../../../core/src" import { hierarchy as hierarchyFunctions, common } from "../../../core/src"
const pipe = common.$
const SNIPPET_EDITORS = { const SNIPPET_EDITORS = {
MAP: "Map", MAP: "Map",
FILTER: "Filter", FILTER: "Filter",
@ -19,25 +17,26 @@
let indexableRecords = [] let indexableRecords = []
let currentSnippetEditor = SNIPPET_EDITORS.MAP let currentSnippetEditor = SNIPPET_EDITORS.MAP
const indexableRecordsFromIndex = compose(
map(node => ({
node,
isallowed: index.allowedRecordNodeIds.some(id => node.nodeId === id),
})),
filter(hierarchyFunctions.isRecord),
filter(hierarchyFunctions.isDecendant(index.parent())),
hierarchyFunctions.getFlattenedHierarchy
)
store.subscribe($store => { store.subscribe($store => {
index = $store.currentNode index = $store.currentNode
indexableRecords = pipe( indexableRecords = indexableRecordsFromIndex($store.hierarchy)
$store.hierarchy,
[
hierarchyFunctions.getFlattenedHierarchy,
filter(hierarchyFunctions.isDecendant(index.parent())),
filter(hierarchyFunctions.isRecord),
map(node => ({
node,
isallowed: index.allowedRecordNodeIds.some(id => node.nodeId === id),
})),
]
)
}) })
const toggleAllowedRecord = record => { const toggleAllowedRecord = record => {
if (record.isallowed) { if (record.isallowed) {
index.allowedRecordNodeIds = index.allowedRecordNodeIds.filter(id => id !== record.node.nodeId) index.allowedRecordNodeIds = index.allowedRecordNodeIds.filter(
id => id !== record.node.nodeId
)
} else { } else {
index.allowedRecordNodeIds.push(record.node.nodeId) index.allowedRecordNodeIds.push(record.node.nodeId)
} }

View File

@ -1,7 +1,7 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { store, backendUiStore } from "../../builderStore" import { store, backendUiStore } from "../../builderStore"
import { last } from "lodash/fp"; import { tap, get, find, last, compose, flatten, map } from "lodash/fp"
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"
@ -15,31 +15,49 @@
let selectedView = "" let selectedView = ""
let modalOpen = false let modalOpen = false
let data = []
let headers = [] let headers = []
let selectedRecord let views = []
let currentPage = 0 let currentPage = 0
$: views = $store.hierarchy.indexes $: views = $backendUiStore.selectedRecord
? childViewsForRecord($store.hierarchy)
: $store.hierarchy.indexes
$: currentAppInfo = { $: currentAppInfo = {
appname: $store.appname, appname: $store.appname,
instanceId: $backendUiStore.selectedDatabase.id, instanceId: $backendUiStore.selectedDatabase.id,
} }
$: data = $backendUiStore.selectedView.records.slice( // $: data =
currentPage * ITEMS_PER_PAGE, // $backendUiStore.selectedDatabase &&
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE // $backendUiStore.selectedView.records.slice(
// currentPage * ITEMS_PER_PAGE,
// currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
// )
$: fetchRecordsForView(
$backendUiStore.selectedView,
$backendUiStore.selectedDatabase
).then(records => {
data = records
headers = getSchema($backendUiStore.selectedView).map(get("name"))
})
const childViewsForRecord = compose(
flatten,
map("indexes"),
get("children")
) )
$: showTable = currentAppInfo.instanceId && views.length > 0
const getSchema = getIndexSchema($store.hierarchy) const getSchema = getIndexSchema($store.hierarchy)
async function fetchRecordsForView(viewName) { async function fetchRecordsForView(view, instance) {
const recordsForIndex = await api.fetchDataForView(viewName, currentAppInfo) const viewName = $backendUiStore.selectedRecord
backendUiStore.update(state => { ? `${$backendUiStore.selectedRecord.type}/`
state.selectedView.records = recordsForIndex : view.name
if (state.selectedView.records.length > 0) { return await api.fetchDataForView(view.name, {
headers = Object.keys(recordsForIndex[0]) appname: $store.appname,
} instanceId: instance.id,
return state
}) })
} }
@ -47,26 +65,20 @@
backendUiStore.update(state => { backendUiStore.update(state => {
state.selectedRecord = record state.selectedRecord = record
state.breadcrumbs = [state.selectedDatabase.name, record.id] state.breadcrumbs = [state.selectedDatabase.name, record.id]
// Update the dropdown with the child indexes for that record
return state return state
}) })
} }
onMount(async () => {
if (views.length > 0) {
await fetchRecordsForView(views[0].name, currentAppInfo)
}
})
</script> </script>
<section> <section>
<div class="table-controls"> <div class="table-controls">
<h4 class="budibase__title--3"> <h4 class="budibase__title--3">{last($backendUiStore.breadcrumbs)}</h4>
{last($backendUiStore.breadcrumbs)}
</h4>
<Select <Select
icon="ri-eye-line" icon="ri-eye-line"
on:change={e => fetchRecordsForView(e.target.value)}> on:change={e => {
const view = e.target.value
backendUiStore.actions.views.select(view)
}}>
{#each views as view} {#each views as view}
<option value={view.name}>{view.name}</option> <option value={view.name}>{view.name}</option>
{/each} {/each}

View File

@ -1,6 +1,12 @@
import api from "../../builderStore/api" import api from "../../builderStore/api"
import { getNewRecord, getNewInstance } from "../../common/core" import { getNewRecord, getNewInstance } from "../../common/core"
export async function createUser(user, { appname, instanceId }) {
const CREATE_USER_URL = `/_builder/instance/${appname}/${instanceId}/api/createUser`
const response = await api.post(CREATE_USER_URL, user)
return await response.json()
}
export async function createDatabase(appname, instanceName) { export async function createDatabase(appname, instanceName) {
const CREATE_DATABASE_URL = `/_builder/instance/_master/0/api/record/` const CREATE_DATABASE_URL = `/_builder/instance/_master/0/api/record/`
const database = getNewInstance(appname, instanceName) const database = getNewInstance(appname, instanceName)

View File

@ -1,30 +1,51 @@
<script> <script>
import Modal from "../../../common/Modal.svelte" import Modal from "../../../common/Modal.svelte"
import { store } from "../../../builderStore" import { store, backendUiStore } from "../../../builderStore"
import ActionButton from "../../../common/ActionButton.svelte" import ActionButton from "../../../common/ActionButton.svelte"
import * as api from "../api" import * as api from "../api"
export let onClosed export let onClosed
let userName let username
let password
let accessLevels = []
$: valid = username && password && accessLevels.length
$: currentAppInfo = {
appname: $store.appname,
instanceId: $backendUiStore.selectedDatabase.id,
}
async function createUser() { async function createUser() {
const response = await api.createUser($store.appname, userName) const response = await api.createUser(
store.createUserForInstance(response) {
username,
password,
accessLevels,
enabled: true,
},
currentAppInfo
)
onClosed() onClosed()
} }
</script> </script>
<section> <form class="uk-form-stacked">
User Name <label class="uk-form-label" for="form-stacked-text">Username</label>
<input class="uk-input" type="text" bind:value={userName} /> <input class="uk-input" type="text" bind:value={username} />
<label class="uk-form-label" for="form-stacked-text">Password</label>
<input class="uk-input" type="password" bind:value={password} />
<label class="uk-form-label" for="form-stacked-text">Access Levels</label>
<select multiple bind:value={accessLevels}>
{#each $store.accessLevels.levels as level}
<option value={level.name}>{level.name}</option>
{/each}
</select>
<footer> <footer>
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton disabled={!userName} on:click={createUser}> <ActionButton disabled={!valid} on:click={createUser}>Save</ActionButton>
Save
</ActionButton>
</footer> </footer>
</section> </form>
<style> <style>
footer { footer {

View File

@ -30,7 +30,10 @@
<div class="components-list-container"> <div class="components-list-container">
<div class="nav-group-header"> <div class="nav-group-header">
<div class="hierarchy-title">Users</div> <div class="hierarchy-title">Users</div>
<i class="ri-add-line" /> <i
class="ri-add-line hoverable"
on:click={() => backendUiStore.actions.modals.show('USER')}
/>
</div> </div>
</div> </div>