Merge branch 'new-backend' of github.com:Budibase/budibase into new-backend
This commit is contained in:
commit
1cc2991d18
|
@ -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": {
|
||||||
|
|
|
@ -105,7 +105,9 @@ const lodash_fp_exports = [
|
||||||
"toPairs",
|
"toPairs",
|
||||||
"remove",
|
"remove",
|
||||||
"findIndex",
|
"findIndex",
|
||||||
"compose"
|
"compose",
|
||||||
|
"get",
|
||||||
|
"tap"
|
||||||
]
|
]
|
||||||
|
|
||||||
const lodash_exports = [
|
const lodash_exports = [
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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: () => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,58 +15,70 @@
|
||||||
|
|
||||||
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
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function drillIntoRecord(record) {
|
function drillIntoRecord(record) {
|
||||||
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}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue