Updates backend routing
This merges in the changes to enable routing for the backend
This commit is contained in:
commit
5c16770e3b
|
@ -50,6 +50,7 @@
|
||||||
"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-simple-modal": "^0.3.0",
|
||||||
"uikit": "^3.1.7"
|
"uikit": "^3.1.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -58,7 +59,7 @@
|
||||||
"@babel/preset-env": "^7.5.5",
|
"@babel/preset-env": "^7.5.5",
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"@rollup/plugin-alias": "^3.0.1",
|
"@rollup/plugin-alias": "^3.0.1",
|
||||||
"@sveltech/routify": "1.5.0-beta.16",
|
"@sveltech/routify": "1.5.0-beta.40",
|
||||||
"babel-jest": "^24.8.0",
|
"babel-jest": "^24.8.0",
|
||||||
"browser-sync": "^2.26.7",
|
"browser-sync": "^2.26.7",
|
||||||
"http-proxy-middleware": "^0.19.1",
|
"http-proxy-middleware": "^0.19.1",
|
||||||
|
|
|
@ -8,38 +8,10 @@ import { terser } from "rollup-plugin-terser"
|
||||||
import builtins from "rollup-plugin-node-builtins"
|
import builtins from "rollup-plugin-node-builtins"
|
||||||
import nodeglobals from "rollup-plugin-node-globals"
|
import nodeglobals from "rollup-plugin-node-globals"
|
||||||
import copy from "rollup-plugin-copy"
|
import copy from "rollup-plugin-copy"
|
||||||
import browsersync from "rollup-plugin-browsersync"
|
|
||||||
import proxy from "http-proxy-middleware"
|
|
||||||
import replace from "rollup-plugin-replace"
|
import replace from "rollup-plugin-replace"
|
||||||
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|
||||||
const target = "http://localhost:4001"
|
|
||||||
const _builderProxy = proxy("/_builder", {
|
|
||||||
target: "http://localhost:3000",
|
|
||||||
pathRewrite: { "^/_builder": "" },
|
|
||||||
})
|
|
||||||
|
|
||||||
const apiProxy = proxy(
|
|
||||||
[
|
|
||||||
"/_builder/assets/**",
|
|
||||||
"/_builder/api/**",
|
|
||||||
"/_builder/**/componentlibrary",
|
|
||||||
"/_builder/instance/**",
|
|
||||||
],
|
|
||||||
{
|
|
||||||
target,
|
|
||||||
logLevel: "debug",
|
|
||||||
changeOrigin: true,
|
|
||||||
cookieDomainRewrite: true,
|
|
||||||
onProxyReq(proxyReq) {
|
|
||||||
if (proxyReq.getHeader("origin")) {
|
|
||||||
proxyReq.setHeader("origin", target)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const production = !process.env.ROLLUP_WATCH
|
const production = !process.env.ROLLUP_WATCH
|
||||||
|
|
||||||
const lodash_fp_exports = [
|
const lodash_fp_exports = [
|
||||||
|
@ -230,34 +202,9 @@ export default {
|
||||||
// Watch the `dist` directory and refresh the
|
// Watch the `dist` directory and refresh the
|
||||||
// browser on changes when not in production
|
// browser on changes when not in production
|
||||||
!production && livereload(outputpath),
|
!production && livereload(outputpath),
|
||||||
!production &&
|
|
||||||
browsersync({
|
|
||||||
server: outputpath,
|
|
||||||
middleware: [apiProxy, _builderProxy],
|
|
||||||
}),
|
|
||||||
|
|
||||||
// If we're building for production (npm run build
|
// If we're building for production (npm run build
|
||||||
// instead of npm run dev), minify
|
// instead of npm run dev), minify
|
||||||
production && terser(),
|
production && terser(),
|
||||||
],
|
],
|
||||||
watch: {
|
|
||||||
clearScreen: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
function serve() {
|
|
||||||
let started = false
|
|
||||||
|
|
||||||
return {
|
|
||||||
writeBundle() {
|
|
||||||
if (!started) {
|
|
||||||
started = true
|
|
||||||
|
|
||||||
require("child_process").spawn("npm", ["run", "start"], {
|
|
||||||
stdio: ["ignore", "inherit", "inherit"],
|
|
||||||
shell: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,17 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
import NoPackage from "./NoPackage.svelte"
|
import Modal from "svelte-simple-modal"
|
||||||
import PackageRoot from "./PackageRoot.svelte"
|
|
||||||
import Settings from "./Settings.svelte"
|
|
||||||
import { store, initialise } from "builderStore"
|
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import IconButton from "components/common/IconButton.svelte"
|
import { Router, basepath } from "@sveltech/routify"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import { routes } from "@sveltech/routify/tmp/routes"
|
||||||
|
import { store, initialise } from "builderStore"
|
||||||
import AppNotification, {
|
import AppNotification, {
|
||||||
showAppNotification,
|
showAppNotification,
|
||||||
} from "components/common/AppNotification.svelte"
|
} from "components/common/AppNotification.svelte"
|
||||||
|
|
||||||
let init = initialise()
|
|
||||||
|
|
||||||
function showErrorBanner() {
|
function showErrorBanner() {
|
||||||
showAppNotification({
|
showAppNotification({
|
||||||
status: "danger",
|
status: "danger",
|
||||||
|
@ -24,57 +20,12 @@
|
||||||
window.addEventListener("error", showErrorBanner)
|
window.addEventListener("error", showErrorBanner)
|
||||||
window.addEventListener("unhandledrejection", showErrorBanner)
|
window.addEventListener("unhandledrejection", showErrorBanner)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$basepath = "/_builder"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<AppNotification />
|
||||||
<AppNotification />
|
|
||||||
{#await init}
|
|
||||||
<div class="spinner-container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{:then result}
|
|
||||||
|
|
||||||
{#if $store.hasAppPackage}
|
<Modal>
|
||||||
<PackageRoot />
|
<Router {routes} />
|
||||||
{:else}
|
</Modal>
|
||||||
<NoPackage />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{:catch err}
|
|
||||||
<h1 style="color:red">{err}</h1>
|
|
||||||
{/await}
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<div class="settings">
|
|
||||||
<IconButton icon="settings"
|
|
||||||
on:click={store.showSettings}/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{#if $store.useAnalytics}
|
|
||||||
<iframe src="https://marblekirby.github.io/bb-analytics.html" width="0" height="0" style="visibility:hidden;display:none"/>
|
|
||||||
{/if}
|
|
||||||
-->
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
main {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
font-family: "Roboto", Helvetica, Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 25px;
|
|
||||||
right: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner-container {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
<script>
|
|
||||||
import BackendNav from "components/nav/BackendNav.svelte"
|
|
||||||
import SchemaManagementDrawer from "components/nav/SchemaManagementDrawer.svelte"
|
|
||||||
import Database from "components/database/DatabaseRoot.svelte"
|
|
||||||
import UserInterface from "components/userInterface/UserInterfaceRoot.svelte"
|
|
||||||
import ActionsAndTriggers from "components/actionsAndTriggers/ActionsAndTriggersRoot.svelte"
|
|
||||||
import AccessLevels from "components/accessLevels/AccessLevelsRoot.svelte"
|
|
||||||
import ComingSoon from "components/common/ComingSoon.svelte"
|
|
||||||
|
|
||||||
import { store, backendUiStore } from "builderStore"
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="root">
|
|
||||||
<div class="nav">
|
|
||||||
<BackendNav />
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
{#if $backendUiStore.leftNavItem === 'DATABASE'}
|
|
||||||
<Database />
|
|
||||||
{:else if $backendUiStore.leftNavItem === 'ACTIONS'}
|
|
||||||
<ActionsAndTriggers />
|
|
||||||
{:else if $backendUiStore.leftNavItem === 'ACCESS_LEVELS'}
|
|
||||||
<AccessLevels />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div class="nav">
|
|
||||||
<SchemaManagementDrawer />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
margin: 20px 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav {
|
|
||||||
overflow: auto;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
width: 275px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,172 +0,0 @@
|
||||||
<script>
|
|
||||||
import IconButton from "components/common/IconButton.svelte"
|
|
||||||
import { store } from "builderStore"
|
|
||||||
import UserInterfaceRoot from "components/userInterface/UserInterfaceRoot.svelte"
|
|
||||||
import BackendRoot from "./BackendRoot.svelte"
|
|
||||||
import { fade } from "svelte/transition"
|
|
||||||
import { SettingsIcon, PreviewIcon } from "components/common/Icons/"
|
|
||||||
|
|
||||||
const TABS = {
|
|
||||||
BACKEND: "backend",
|
|
||||||
FRONTEND: "frontend",
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedTab = TABS.BACKEND
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="root">
|
|
||||||
|
|
||||||
<div class="top-nav">
|
|
||||||
<div class="topleftnav">
|
|
||||||
<button class="home-logo">
|
|
||||||
<img src="/_builder/assets/budibase-emblem-white.svg" />
|
|
||||||
</button>
|
|
||||||
<!-- <IconButton icon="home"
|
|
||||||
color="var(--slate)"
|
|
||||||
hoverColor="var(--secondary75)"/> -->
|
|
||||||
<span
|
|
||||||
class:active={selectedTab === TABS.BACKEND}
|
|
||||||
class="topnavitem"
|
|
||||||
on:click={() => (selectedTab = TABS.BACKEND)}>
|
|
||||||
Backend
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
class:active={selectedTab === TABS.FRONTEND}
|
|
||||||
class="topnavitem"
|
|
||||||
on:click={() => (selectedTab = TABS.FRONTEND)}>
|
|
||||||
Frontend
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="toprightnav">
|
|
||||||
<span
|
|
||||||
class:active={selectedTab === TABS.FRONTEND}
|
|
||||||
class="topnavitemright"
|
|
||||||
on:click={() => selectedTab === TABS.FRONTEND}>
|
|
||||||
<SettingsIcon />
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
class:active={selectedTab === TABS.FRONTEND}
|
|
||||||
class="topnavitemright"
|
|
||||||
on:click={() => selectedTab === TABS.FRONTEND}>
|
|
||||||
<PreviewIcon />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content">
|
|
||||||
{#if selectedTab === TABS.BACKEND}
|
|
||||||
<div in:fade out:fade>
|
|
||||||
<BackendRoot />
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div in:fade out:fade>
|
|
||||||
<UserInterfaceRoot />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-nav {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
height: 48px;
|
|
||||||
background: #0d203b;
|
|
||||||
padding: 0px 20px 0 20px;
|
|
||||||
display: flex;
|
|
||||||
box-sizing: border-box;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
width: 100%;
|
|
||||||
height: 100px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content > div {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toprightnav {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topleftnav {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topnavitem {
|
|
||||||
cursor: pointer;
|
|
||||||
color: rgb(255, 255, 255, 0.6);
|
|
||||||
margin: 0px 10px;
|
|
||||||
padding-top: 4px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1rem;
|
|
||||||
height: 100%;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topnavitem:hover {
|
|
||||||
color: rgb(255, 255, 255, 0.8);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
color: white;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topnavitemright {
|
|
||||||
cursor: pointer;
|
|
||||||
color: rgb(255, 255, 255, 0.6);
|
|
||||||
margin: 0px 5px;
|
|
||||||
padding-top: 4px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1rem;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topnavitemright:hover {
|
|
||||||
color: rgb(255, 255, 255, 0.8);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-logo {
|
|
||||||
border-style: none;
|
|
||||||
background-color: rgba(0, 0, 0, 0);
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
height: 40px;
|
|
||||||
padding: 8px 10px 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-logo:hover {
|
|
||||||
color: var(--hovercolor);
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-logo:active {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-logo img {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -10,20 +10,7 @@ export const initialise = async () => {
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (process.env.NODE_ENV === "production") {
|
||||||
LogRocket.init("knlald/budibase")
|
LogRocket.init("knlald/budibase")
|
||||||
}
|
}
|
||||||
setupRouter(store)
|
|
||||||
await store.initialise()
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setupRouter = writable => {
|
|
||||||
const pushState = history.pushState
|
|
||||||
history.pushState = () => {
|
|
||||||
pushState.apply(history, [writable])
|
|
||||||
writable.initialise()
|
|
||||||
}
|
|
||||||
window.addEventListener("hashchange", () => {
|
|
||||||
writable.initialise()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ import {
|
||||||
|
|
||||||
export const getBackendUiStore = () => {
|
export const getBackendUiStore = () => {
|
||||||
const INITIAL_BACKEND_UI_STATE = {
|
const INITIAL_BACKEND_UI_STATE = {
|
||||||
leftNavItem: "DATABASE",
|
|
||||||
selectedView: {
|
selectedView: {
|
||||||
records: [],
|
records: [],
|
||||||
name: "",
|
name: "",
|
||||||
|
@ -27,7 +26,6 @@ export const getBackendUiStore = () => {
|
||||||
const store = writable(INITIAL_BACKEND_UI_STATE)
|
const store = writable(INITIAL_BACKEND_UI_STATE)
|
||||||
|
|
||||||
store.actions = {
|
store.actions = {
|
||||||
navigate: name => store.update(state => ({ ...state, leftNavItem: name })),
|
|
||||||
database: {
|
database: {
|
||||||
select: db =>
|
select: db =>
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -60,10 +58,6 @@ export const getBackendUiStore = () => {
|
||||||
return state
|
return state
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
modals: {
|
|
||||||
show: modal => store.update(state => ({ ...state, visibleModal: modal })),
|
|
||||||
hide: () => store.update(state => ({ ...state, visibleModal: null })),
|
|
||||||
},
|
|
||||||
users: {
|
users: {
|
||||||
create: user =>
|
create: user =>
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -302,7 +296,7 @@ export const deleteLevel = store => level => {
|
||||||
state.accessLevels.levels = state.accessLevels.levels.filter(
|
state.accessLevels.levels = state.accessLevels.levels.filter(
|
||||||
t => t.name !== level.name
|
t => t.name !== level.name
|
||||||
)
|
)
|
||||||
incrementAccessLevelsVersion(s)
|
incrementAccessLevelsVersion(state)
|
||||||
saveBackend(state)
|
saveBackend(state)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//
|
||||||
import { filter, cloneDeep, last, concat, isEmpty, values } from "lodash/fp"
|
import { filter, cloneDeep, last, concat, isEmpty, values } from "lodash/fp"
|
||||||
import { pipe, getNode, constructHierarchy } from "components/common/core"
|
import { pipe, getNode, constructHierarchy } from "components/common/core"
|
||||||
import * as backendStoreActions from "./backend"
|
import * as backendStoreActions from "./backend"
|
||||||
|
@ -49,7 +50,7 @@ export const getStore = () => {
|
||||||
|
|
||||||
const store = writable(initial)
|
const store = writable(initial)
|
||||||
|
|
||||||
store.initialise = initialise(store, initial)
|
store.setPackage = setPackage(store, initial)
|
||||||
|
|
||||||
store.newChildRecord = backendStoreActions.newRecord(store, false)
|
store.newChildRecord = backendStoreActions.newRecord(store, false)
|
||||||
store.newRootRecord = backendStoreActions.newRecord(store, true)
|
store.newRootRecord = backendStoreActions.newRecord(store, true)
|
||||||
|
@ -100,26 +101,12 @@ export const getStore = () => {
|
||||||
|
|
||||||
export default getStore
|
export default getStore
|
||||||
|
|
||||||
const initialise = (store, initial) => async () => {
|
const setPackage = (store, initial) => async (pkg) => {
|
||||||
appname = window.location.hash
|
|
||||||
? last(window.location.hash.substr(1).split("/"))
|
|
||||||
: ""
|
|
||||||
|
|
||||||
if (!appname) {
|
|
||||||
initial.apps = await api.get(`/_builder/api/apps`).then(r => r.json())
|
|
||||||
initial.hasAppPackage = false
|
|
||||||
store.set(initial)
|
|
||||||
return initial
|
|
||||||
}
|
|
||||||
|
|
||||||
const pkg = await api
|
|
||||||
.get(`/_builder/api/${appname}/appPackage`)
|
|
||||||
.then(r => r.json())
|
|
||||||
|
|
||||||
const [main_screens, unauth_screens] = await Promise.all([
|
const [main_screens, unauth_screens] = await Promise.all([
|
||||||
api.get(`/_builder/api/${appname}/pages/main/screens`).then(r => r.json()),
|
api.get(`/_builder/api/${pkg.application.name}/pages/main/screens`).then(r => r.json()),
|
||||||
api
|
api
|
||||||
.get(`/_builder/api/${appname}/pages/unauthenticated/screens`)
|
.get(`/_builder/api/${pkg.application.name}/pages/unauthenticated/screens`)
|
||||||
.then(r => r.json()),
|
.then(r => r.json()),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -134,12 +121,12 @@ const initialise = (store, initial) => async () => {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
initial.libraries = await loadLibs(appname, pkg)
|
initial.libraries = await loadLibs(pkg.application.name, pkg)
|
||||||
initial.loadLibraryUrls = pageName => {
|
initial.loadLibraryUrls = pageName => {
|
||||||
const libs = libUrlsForPreview(pkg, pageName)
|
const libs = libUrlsForPreview(pkg, pageName)
|
||||||
return libs
|
return libs
|
||||||
}
|
}
|
||||||
initial.appname = appname
|
initial.appname = pkg.application.name
|
||||||
initial.pages = pkg.pages
|
initial.pages = pkg.pages
|
||||||
initial.hasAppPackage = true
|
initial.hasAppPackage = true
|
||||||
initial.hierarchy = pkg.appDefinition.hierarchy
|
initial.hierarchy = pkg.appDefinition.hierarchy
|
||||||
|
@ -377,7 +364,7 @@ const savePage = store => async page => {
|
||||||
|
|
||||||
const addComponentLibrary = store => async lib => {
|
const addComponentLibrary = store => async lib => {
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/_builder/api/${appname}/componentlibrary?lib=${encodeURI(lib)}`,
|
`/_builder/api/${s.appname}/componentlibrary?lib=${encodeURI(lib)}`,
|
||||||
undefined,
|
undefined,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
@ -436,7 +423,7 @@ const removeStylesheet = store => stylesheet => {
|
||||||
const _savePage = async s => {
|
const _savePage = async s => {
|
||||||
const page = s.pages[s.currentPageName]
|
const page = s.pages[s.currentPageName]
|
||||||
|
|
||||||
await api.post(`/_builder/api/${appname}/pages/${s.currentPageName}`, {
|
await api.post(`/_builder/api/${s.appname}/pages/${s.currentPageName}`, {
|
||||||
page: { componentLibraries: s.pages.componentLibraries, ...page },
|
page: { componentLibraries: s.pages.componentLibraries, ...page },
|
||||||
uiFunctions: s.currentPageFunctions,
|
uiFunctions: s.currentPageFunctions,
|
||||||
screens: page._screens,
|
screens: page._screens,
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
export let allLevels
|
export let allLevels
|
||||||
export let hierarchy
|
export let hierarchy
|
||||||
export let actions
|
export let actions
|
||||||
|
export let close
|
||||||
|
export let title
|
||||||
|
|
||||||
let errors = []
|
let errors = []
|
||||||
let clonedLevel = cloneDeep(level)
|
let clonedLevel = cloneDeep(level)
|
||||||
|
@ -39,8 +41,8 @@
|
||||||
|
|
||||||
const getPermissionName = perm =>
|
const getPermissionName = perm =>
|
||||||
perm.nodeKey
|
perm.nodeKey
|
||||||
? `${perm.type} - ${nodeNameFromNodeKey(hierarchy, perm.nodeKey)}`
|
? `${perm.type} - ${nodeNameFromNodeKey(hierarchy, perm.nodeKey)}`
|
||||||
: perm.type
|
: perm.type
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
const newLevels = isNew
|
const newLevels = isNew
|
||||||
|
@ -52,6 +54,7 @@
|
||||||
if (errors.length > 0) return
|
if (errors.length > 0) return
|
||||||
|
|
||||||
onFinished(clonedLevel)
|
onFinished(clonedLevel)
|
||||||
|
close()
|
||||||
}
|
}
|
||||||
|
|
||||||
const permissionChanged = perm => ev => {
|
const permissionChanged = perm => ev => {
|
||||||
|
@ -70,9 +73,13 @@
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
|
<div class="uk-modal-header">
|
||||||
|
<h4 class="budibase__title--4">{title}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ErrorsBox {errors} />
|
<ErrorsBox {errors} />
|
||||||
|
|
||||||
<form class="uk-form-horizontal">
|
<form on:submit|preventDefault class="uk-form-horizontal">
|
||||||
|
|
||||||
<Textbox label="Access Level Name" bind:text={clonedLevel.name} />
|
<Textbox label="Access Level Name" bind:text={clonedLevel.name} />
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
|
|
||||||
<ErrorsBox {errors} />
|
<ErrorsBox {errors} />
|
||||||
|
|
||||||
<form class="uk-form-horizontal">
|
<form on:submit|preventDefault class="uk-form-horizontal">
|
||||||
|
|
||||||
<Textbox label="Name" bind:text={clonedAction.name} />
|
<Textbox label="Name" bind:text={clonedAction.name} />
|
||||||
<Textbox
|
<Textbox
|
||||||
|
|
|
@ -22,10 +22,7 @@
|
||||||
let cancel = () => onFinished()
|
let cancel = () => onFinished()
|
||||||
let save = () => {
|
let save = () => {
|
||||||
const newTriggersList = [
|
const newTriggersList = [
|
||||||
...pipe(
|
...pipe(allTriggers, [filter(t => t !== trigger)]),
|
||||||
allTriggers,
|
|
||||||
[filter(t => t !== trigger)]
|
|
||||||
),
|
|
||||||
clonedTrigger,
|
clonedTrigger,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -43,7 +40,7 @@
|
||||||
|
|
||||||
<ErrorsBox {errors} style="margin-bottom:20px" />
|
<ErrorsBox {errors} style="margin-bottom:20px" />
|
||||||
|
|
||||||
<form class="uk-form-horizontal">
|
<form on:submit|preventDefault class="uk-form-horizontal">
|
||||||
|
|
||||||
<Dropdown
|
<Dropdown
|
||||||
label="Event"
|
label="Event"
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
<script>
|
|
||||||
import ModelView from "./ModelView.svelte"
|
|
||||||
import IndexView from "./IndexView.svelte"
|
|
||||||
import ModelDataTable from "./ModelDataTable"
|
|
||||||
import { store, backendUiStore } from "builderStore"
|
|
||||||
import getIcon from "components/common/icon"
|
|
||||||
import DropdownButton from "components/common/DropdownButton.svelte"
|
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import * as api from "./ModelDataTable/api"
|
|
||||||
import {
|
|
||||||
CreateEditRecordModal,
|
|
||||||
CreateEditModelModal,
|
|
||||||
CreateEditViewModal,
|
|
||||||
CreateDatabaseModal,
|
|
||||||
DeleteRecordModal,
|
|
||||||
CreateUserModal,
|
|
||||||
} from "./ModelDataTable/modals"
|
|
||||||
|
|
||||||
let selectedRecord
|
|
||||||
|
|
||||||
async function selectRecord(record) {
|
|
||||||
selectedRecord = await api.loadRecord(record.key, {
|
|
||||||
appname: $store.appname,
|
|
||||||
instanceId: $backendUiStore.selectedDatabase.id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function onClosed() {
|
|
||||||
backendUiStore.actions.modals.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
$: recordOpen = $backendUiStore.visibleModal === "RECORD"
|
|
||||||
$: modelOpen = $backendUiStore.visibleModal === "MODEL"
|
|
||||||
$: viewOpen = $backendUiStore.visibleModal === "VIEW"
|
|
||||||
$: databaseOpen = $backendUiStore.visibleModal === "DATABASE"
|
|
||||||
$: deleteRecordOpen = $backendUiStore.visibleModal === "DELETE_RECORD"
|
|
||||||
$: userOpen = $backendUiStore.visibleModal === "USER"
|
|
||||||
$: breadcrumbs = $backendUiStore.breadcrumbs.join(" / ")
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Modal isOpen={!!$backendUiStore.visibleModal} {onClosed}>
|
|
||||||
{#if recordOpen}
|
|
||||||
<CreateEditRecordModal record={selectedRecord} {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if modelOpen}
|
|
||||||
<CreateEditModelModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if viewOpen}
|
|
||||||
<CreateEditViewModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if databaseOpen}
|
|
||||||
<CreateDatabaseModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if deleteRecordOpen}
|
|
||||||
<DeleteRecordModal record={selectedRecord} {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if userOpen}
|
|
||||||
<CreateUserModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<div class="root">
|
|
||||||
<div class="node-view">
|
|
||||||
<div class="database-actions">
|
|
||||||
<div class="breadcrumb">{breadcrumbs}</div>
|
|
||||||
{#if $backendUiStore.selectedDatabase.id}
|
|
||||||
<ActionButton
|
|
||||||
primary
|
|
||||||
on:click={() => {
|
|
||||||
selectedRecord = null
|
|
||||||
backendUiStore.actions.modals.show('RECORD')
|
|
||||||
}}>
|
|
||||||
Create new record
|
|
||||||
</ActionButton>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{#if $backendUiStore.selectedDatabase.id}
|
|
||||||
<ModelDataTable {selectRecord} />
|
|
||||||
{:else}Please select a database{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-view {
|
|
||||||
overflow-y: auto;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumb {
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--secondary60);
|
|
||||||
}
|
|
||||||
|
|
||||||
.database-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -67,7 +67,7 @@
|
||||||
|
|
||||||
<ErrorsBox {errors} />
|
<ErrorsBox {errors} />
|
||||||
|
|
||||||
<form class="uk-form-stacked">
|
<form on:submit|preventDefault class="uk-form-stacked">
|
||||||
<Textbox label="Name" bind:text={clonedField.name} />
|
<Textbox label="Name" bind:text={clonedField.name} />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
label="Type"
|
label="Type"
|
||||||
|
@ -136,18 +136,19 @@
|
||||||
bind:value={clonedField.typeOptions.maxLength} />
|
bind:value={clonedField.typeOptions.maxLength} />
|
||||||
{/if}
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<footer>
|
|
||||||
<ActionButton primary on:click={save}>Save</ActionButton>
|
|
||||||
<ActionButton alert on:click={() => onFinished(false)}>Cancel</ActionButton>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
|
<footer>
|
||||||
|
<ActionButton primary on:click={save}>Save</ActionButton>
|
||||||
|
<ActionButton alert on:click={() => onFinished(false)}>Cancel</ActionButton>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.root {
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
footer {
|
footer {
|
||||||
position: absolute;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
width: 100%;
|
border-radius: 0 0 5px 5px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
<i class="ri-eye-line button--toggled" />
|
<i class="ri-eye-line button--toggled" />
|
||||||
<h3 class="budibase__title--3">Create / Edit View</h3>
|
<h3 class="budibase__title--3">Create / Edit View</h3>
|
||||||
</heading>
|
</heading>
|
||||||
<form class="uk-form-stacked root">
|
<form on:submit|preventDefault class="uk-form-stacked root">
|
||||||
<h4 class="budibase__label--big">Settings</h4>
|
<h4 class="budibase__label--big">Settings</h4>
|
||||||
{#if $store.errors && $store.errors.length > 0}
|
{#if $store.errors && $store.errors.length > 0}
|
||||||
<ErrorsBox errors={$store.errors} />
|
<ErrorsBox errors={$store.errors} />
|
||||||
|
@ -144,6 +144,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
heading {
|
heading {
|
||||||
|
padding: 20px 20px 0 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount, getContext } from "svelte"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import {
|
import {
|
||||||
tap,
|
tap,
|
||||||
|
@ -17,10 +17,39 @@
|
||||||
import { getIndexSchema } from "components/common/core"
|
import { getIndexSchema } from "components/common/core"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import TablePagination from "./TablePagination.svelte"
|
import TablePagination from "./TablePagination.svelte"
|
||||||
import { DeleteRecordModal } from "./modals"
|
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
|
||||||
import * as api from "./api"
|
import * as api from "./api"
|
||||||
|
|
||||||
export let selectRecord
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
const editRecord = async row => {
|
||||||
|
open(
|
||||||
|
CreateEditRecordModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
record: await selectRecord(row),
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteRecord = async row => {
|
||||||
|
open(
|
||||||
|
DeleteRecordModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
record: await selectRecord(row),
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectRecord(record) {
|
||||||
|
return await api.loadRecord(record.key, {
|
||||||
|
appname: $store.appname,
|
||||||
|
instanceId: $backendUiStore.selectedDatabase.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 10
|
const ITEMS_PER_PAGE = 10
|
||||||
// Internal headers we want to hide from the user
|
// Internal headers we want to hide from the user
|
||||||
|
@ -56,11 +85,7 @@
|
||||||
|
|
||||||
const getSchema = getIndexSchema($store.hierarchy)
|
const getSchema = getIndexSchema($store.hierarchy)
|
||||||
|
|
||||||
const childViewsForRecord = compose(
|
const childViewsForRecord = compose(flatten, map("indexes"), get("children"))
|
||||||
flatten,
|
|
||||||
map("indexes"),
|
|
||||||
get("children")
|
|
||||||
)
|
|
||||||
|
|
||||||
const hideInternalHeaders = compose(
|
const hideInternalHeaders = compose(
|
||||||
remove(headerName => INTERNAL_HEADERS.includes(headerName)),
|
remove(headerName => INTERNAL_HEADERS.includes(headerName)),
|
||||||
|
@ -133,16 +158,14 @@
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
selectRecord(row)
|
editRecord(row)
|
||||||
backendUiStore.actions.modals.show('RECORD')
|
|
||||||
}}>
|
}}>
|
||||||
<div>Edit</div>
|
<div>Edit</div>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<div
|
<div
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
selectRecord(row)
|
deleteRecord(row)
|
||||||
backendUiStore.actions.modals.show('DELETE_RECORD')
|
|
||||||
}}>
|
}}>
|
||||||
Delete
|
Delete
|
||||||
</div>
|
</div>
|
||||||
|
@ -166,7 +189,6 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
|
import Modal from "components/common/Modal.svelte"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import * as api from "../api"
|
import * as api from "../api"
|
||||||
|
|
||||||
|
@ -15,24 +15,26 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<div>
|
||||||
Database Name
|
<section>
|
||||||
<input class="uk-input" type="text" bind:value={databaseName} />
|
Database Name
|
||||||
|
<input class="uk-input" type="text" bind:value={databaseName} />
|
||||||
|
</section>
|
||||||
<footer>
|
<footer>
|
||||||
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
||||||
<ActionButton disabled={!databaseName} on:click={createDatabase}>
|
<ActionButton disabled={!databaseName} on:click={createDatabase}>
|
||||||
Save
|
Save
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
section {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
footer {
|
footer {
|
||||||
position: absolute;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
|
||||||
import { backendUiStore } from "builderStore"
|
|
||||||
import ModelView from "../../ModelView.svelte"
|
import ModelView from "../../ModelView.svelte"
|
||||||
import * as api from "../api"
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import { compose, map, get, flatten } from "lodash/fp"
|
import { compose, map, get, flatten } from "lodash/fp"
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import Select from "components/common/Select.svelte"
|
import Select from "components/common/Select.svelte"
|
||||||
import {
|
import {
|
||||||
|
@ -68,39 +67,37 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div class="actions">
|
||||||
<h4 class="budibase__title--4">Create / Edit Record</h4>
|
<h4 class="budibase__title--4">Create / Edit Record</h4>
|
||||||
<ErrorsBox {errors} />
|
<ErrorsBox {errors} />
|
||||||
<div class="actions">
|
<form on:submit|preventDefault class="uk-form-stacked">
|
||||||
<form class="uk-form-stacked">
|
{#if !record}
|
||||||
{#if !record}
|
<div class="uk-margin">
|
||||||
<div class="uk-margin">
|
<label class="uk-form-label" for="form-stacked-text">Model</label>
|
||||||
<label class="uk-form-label" for="form-stacked-text">Model</label>
|
<Select bind:value={selectedModel}>
|
||||||
<Select bind:value={selectedModel}>
|
{#each models as model}
|
||||||
{#each models as model}
|
<option value={model}>{model.name}</option>
|
||||||
<option value={model}>{model.name}</option>
|
{/each}
|
||||||
{/each}
|
</Select>
|
||||||
</Select>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
{#each modelFields || [] as field}
|
||||||
{#each modelFields || [] as field}
|
<RecordFieldControl record={editingRecord} {field} {errors} />
|
||||||
<RecordFieldControl record={editingRecord} {field} {errors} />
|
{/each}
|
||||||
{/each}
|
</form>
|
||||||
</form>
|
|
||||||
<footer>
|
|
||||||
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
|
||||||
<ActionButton on:click={saveRecord}>Save</ActionButton>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<footer>
|
||||||
|
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
||||||
|
<ActionButton on:click={saveRecord}>Save</ActionButton>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.actions {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
footer {
|
footer {
|
||||||
position: absolute;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import IndexView from "../../IndexView.svelte"
|
import IndexView from "../../IndexView.svelte"
|
||||||
import * as api from "../api"
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script>
|
<script>
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import * as api from "../api"
|
import * as api from "../api"
|
||||||
|
@ -29,17 +28,19 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="uk-form-stacked">
|
<form on:submit|preventDefault class="uk-form-stacked">
|
||||||
<label class="uk-form-label" for="form-stacked-text">Username</label>
|
<div>
|
||||||
<input class="uk-input" type="text" bind:value={username} />
|
<label class="uk-form-label" for="form-stacked-text">Username</label>
|
||||||
<label class="uk-form-label" for="form-stacked-text">Password</label>
|
<input class="uk-input" type="text" bind:value={username} />
|
||||||
<input class="uk-input" type="password" bind:value={password} />
|
<label class="uk-form-label" for="form-stacked-text">Password</label>
|
||||||
<label class="uk-form-label" for="form-stacked-text">Access Levels</label>
|
<input class="uk-input" type="password" bind:value={password} />
|
||||||
<select multiple bind:value={accessLevels}>
|
<label class="uk-form-label" for="form-stacked-text">Access Levels</label>
|
||||||
{#each $store.accessLevels.levels as level}
|
<select multiple bind:value={accessLevels}>
|
||||||
<option value={level.name}>{level.name}</option>
|
{#each $store.accessLevels.levels as level}
|
||||||
{/each}
|
<option value={level.name}>{level.name}</option>
|
||||||
</select>
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
||||||
<ActionButton disabled={!valid} on:click={createUser}>Save</ActionButton>
|
<ActionButton disabled={!valid} on:click={createUser}>Save</ActionButton>
|
||||||
|
@ -47,13 +48,13 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
div {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
footer {
|
footer {
|
||||||
position: absolute;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,30 +1,28 @@
|
||||||
<script>
|
<script>
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import * as api from "../api"
|
import * as api from "../api"
|
||||||
|
|
||||||
export let record
|
export let record
|
||||||
|
export let onClosed
|
||||||
|
|
||||||
$: currentAppInfo = {
|
$: currentAppInfo = {
|
||||||
appname: $store.appname,
|
appname: $store.appname,
|
||||||
instanceId: $backendUiStore.selectedDatabase.id,
|
instanceId: $backendUiStore.selectedDatabase.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
function onClosed() {
|
|
||||||
backendUiStore.actions.modals.hide()
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<heading>
|
<div class="content">
|
||||||
<i class="ri-information-line alert" />
|
<heading>
|
||||||
<h4 class="budibase__title--4">Delete Record</h4>
|
<i class="ri-information-line alert" />
|
||||||
</heading>
|
<h4 class="budibase__title--4">Delete Record</h4>
|
||||||
<p>
|
</heading>
|
||||||
Are you sure you want to delete this record? All of your data will be
|
<p>
|
||||||
permanently removed. This action cannot be undone.
|
Are you sure you want to delete this record? All of your data will be
|
||||||
</p>
|
permanently removed. This action cannot be undone.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<div class="modal-actions">
|
<div class="modal-actions">
|
||||||
<ActionButton on:click={onClosed}>Cancel</ActionButton>
|
<ActionButton on:click={onClosed}>Cancel</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
|
@ -48,18 +46,17 @@
|
||||||
|
|
||||||
.modal-actions {
|
.modal-actions {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
heading {
|
heading {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
margin: 0 0 0 10px;
|
margin: 0 0 0 10px;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import getIcon from "components/common/icon"
|
import getIcon from "components/common/icon"
|
||||||
import FieldView from "./FieldView.svelte"
|
import FieldView from "./FieldView.svelte"
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import {
|
import {
|
||||||
get,
|
get,
|
||||||
compose,
|
compose,
|
||||||
|
@ -101,24 +100,24 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<heading>
|
||||||
<heading>
|
|
||||||
{#if !editingField}
|
|
||||||
<i class="ri-list-settings-line button--toggled" />
|
|
||||||
<h3 class="budibase__title--3">Create / Edit Model</h3>
|
|
||||||
{:else}
|
|
||||||
<i class="ri-file-list-line button--toggled" />
|
|
||||||
<h3 class="budibase__title--3">Create / Edit Field</h3>
|
|
||||||
{/if}
|
|
||||||
</heading>
|
|
||||||
{#if !editingField}
|
{#if !editingField}
|
||||||
|
<i class="ri-list-settings-line button--toggled" />
|
||||||
|
<h3 class="budibase__title--3">Create / Edit Model</h3>
|
||||||
|
{:else}
|
||||||
|
<i class="ri-file-list-line button--toggled" />
|
||||||
|
<h3 class="budibase__title--3">Create / Edit Field</h3>
|
||||||
|
{/if}
|
||||||
|
</heading>
|
||||||
|
{#if !editingField}
|
||||||
|
<div class="padding">
|
||||||
<h4 class="budibase__label--big">Settings</h4>
|
<h4 class="budibase__label--big">Settings</h4>
|
||||||
|
|
||||||
{#if $store.errors && $store.errors.length > 0}
|
{#if $store.errors && $store.errors.length > 0}
|
||||||
<ErrorsBox errors={$store.errors} />
|
<ErrorsBox errors={$store.errors} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<form class="uk-form-stacked">
|
<form on:submit|preventDefault class="uk-form-stacked">
|
||||||
|
|
||||||
<Textbox label="Name" bind:text={record.name} on:change={nameChanged} />
|
<Textbox label="Name" bind:text={record.name} on:change={nameChanged} />
|
||||||
{#if isChildModel}
|
{#if isChildModel}
|
||||||
|
@ -186,18 +185,18 @@
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
</div>
|
||||||
<FieldView
|
{:else}
|
||||||
field={fieldToEdit}
|
<FieldView
|
||||||
onFinished={onFinishedFieldEdit}
|
field={fieldToEdit}
|
||||||
allFields={record.fields}
|
onFinished={onFinishedFieldEdit}
|
||||||
store={$store} />
|
allFields={record.fields}
|
||||||
{/if}
|
store={$store} />
|
||||||
</div>
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.root {
|
.padding {
|
||||||
height: 100%;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-field {
|
.new-field {
|
||||||
|
@ -226,6 +225,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
heading {
|
heading {
|
||||||
|
padding: 20px 20px 0 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,30 @@
|
||||||
import UsersList from "./UsersList.svelte"
|
import UsersList from "./UsersList.svelte"
|
||||||
import NavItem from "./NavItem.svelte"
|
import NavItem from "./NavItem.svelte"
|
||||||
import getIcon from "components/common/icon"
|
import getIcon from "components/common/icon"
|
||||||
|
import {
|
||||||
|
CreateDatabaseModal,
|
||||||
|
CreateUserModal,
|
||||||
|
} from "components/database/ModelDataTable/modals"
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
const openDatabaseCreator = () => {
|
||||||
|
open(
|
||||||
|
CreateDatabaseModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const openUserCreator = () => {
|
||||||
|
open(
|
||||||
|
CreateUserModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="items-root">
|
<div class="items-root">
|
||||||
|
@ -13,9 +37,7 @@
|
||||||
<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
|
<i class="ri-add-line hoverable" on:click={openDatabaseCreator} />
|
||||||
class="ri-add-line hoverable"
|
|
||||||
on:click={() => backendUiStore.actions.modals.show('DATABASE')} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -29,9 +51,7 @@
|
||||||
<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
|
<i class="ri-add-line hoverable" on:click={openUserCreator} />
|
||||||
class="ri-add-line hoverable"
|
|
||||||
on:click={() => backendUiStore.actions.modals.show('USER')} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -41,7 +61,10 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<NavItem name="ACCESS_LEVELS" label="User Access Levels" />
|
<NavItem
|
||||||
|
name="ACCESS_LEVELS"
|
||||||
|
label="User Access Levels"
|
||||||
|
href="./accesslevels" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
<script>
|
<script>
|
||||||
import { tick, onMount } from "svelte"
|
import { tick, onMount } from "svelte"
|
||||||
|
import { goto } from "@sveltech/routify"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
import getIcon from "../common/icon"
|
|
||||||
import { CheckIcon } from "../common/Icons"
|
import { CheckIcon } from "../common/Icons"
|
||||||
|
|
||||||
$: instances = $store.appInstances
|
$: instances = $store.appInstances
|
||||||
$: views = $store.hierarchy.indexes
|
$: views = $store.hierarchy.indexes
|
||||||
|
|
||||||
async function selectDatabase(database) {
|
async function selectDatabase(database) {
|
||||||
backendUiStore.actions.navigate("DATABASE")
|
|
||||||
backendUiStore.actions.records.select(null)
|
backendUiStore.actions.records.select(null)
|
||||||
backendUiStore.actions.views.select(views[0])
|
backendUiStore.actions.views.select(views[0])
|
||||||
backendUiStore.actions.database.select(database)
|
backendUiStore.actions.database.select(database)
|
||||||
|
@ -25,12 +24,6 @@
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if ($store.appInstances.length > 0) {
|
|
||||||
selectDatabase($store.appInstances[0])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
@ -44,7 +37,9 @@
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
class:active={database.id === $backendUiStore.selectedDatabase.id}
|
class:active={database.id === $backendUiStore.selectedDatabase.id}
|
||||||
on:click={() => selectDatabase(database)}>
|
on:click={() => {
|
||||||
|
$goto(`./database/${database.id}`), selectDatabase(database)
|
||||||
|
}}>
|
||||||
{database.name}
|
{database.name}
|
||||||
</button>
|
</button>
|
||||||
<i
|
<i
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
import { store, backendUiStore } 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"
|
||||||
|
import {
|
||||||
|
CreateEditModelModal,
|
||||||
|
CreateEditViewModal,
|
||||||
|
} from "components/database/ModelDataTable/modals"
|
||||||
|
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
export let level = 0
|
export let level = 0
|
||||||
export let node
|
export let node
|
||||||
|
@ -23,8 +29,15 @@
|
||||||
|
|
||||||
function selectHierarchyItem(node) {
|
function selectHierarchyItem(node) {
|
||||||
store.selectExistingNode(node.nodeId)
|
store.selectExistingNode(node.nodeId)
|
||||||
const modalType = node.type === "index" ? "VIEW" : "MODEL"
|
const modalType =
|
||||||
backendUiStore.actions.modals.show(modalType)
|
node.type === "index" ? CreateEditViewModal : CreateEditModelModal
|
||||||
|
open(
|
||||||
|
modalType,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
<script>
|
<script>
|
||||||
import getIcon from "../common/icon"
|
import { isActive, url, goto } from "@sveltech/routify"
|
||||||
import { backendUiStore } from "builderStore"
|
|
||||||
|
|
||||||
export let name = ""
|
|
||||||
export let label = ""
|
export let label = ""
|
||||||
|
export let href
|
||||||
$: navActive = $backendUiStore.leftNavItem === name
|
|
||||||
|
|
||||||
const setActive = () => backendUiStore.actions.navigate(name)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
on:click={() => $goto(href)}
|
||||||
class="budibase__nav-item backend-nav-item"
|
class="budibase__nav-item backend-nav-item"
|
||||||
class:selected={navActive}
|
class:selected={$isActive(href)}>
|
||||||
on:click={setActive}>
|
|
||||||
{label}
|
{label}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.backend-nav-item {
|
.backend-nav-item {
|
||||||
padding-left: 25px;
|
padding-left: 25px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import HierarchyRow from "./HierarchyRow.svelte"
|
import HierarchyRow from "./HierarchyRow.svelte"
|
||||||
import DropdownButton from "components/common/DropdownButton.svelte"
|
import DropdownButton from "components/common/DropdownButton.svelte"
|
||||||
import NavItem from "./NavItem.svelte"
|
import NavItem from "./NavItem.svelte"
|
||||||
import getIcon from "components/common/icon"
|
import getIcon from "components/common/icon"
|
||||||
|
import {
|
||||||
|
CreateEditModelModal,
|
||||||
|
CreateEditViewModal,
|
||||||
|
} from "components/database/ModelDataTable/modals"
|
||||||
|
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
function newModel() {
|
function newModel() {
|
||||||
if ($store.currentNode) {
|
if ($store.currentNode) {
|
||||||
|
@ -11,12 +18,24 @@
|
||||||
} else {
|
} else {
|
||||||
store.newRootRecord()
|
store.newRootRecord()
|
||||||
}
|
}
|
||||||
backendUiStore.actions.modals.show("MODEL")
|
open(
|
||||||
|
CreateEditModelModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function newView() {
|
function newView() {
|
||||||
store.newRootIndex()
|
store.newRootIndex()
|
||||||
backendUiStore.actions.modals.show("VIEW")
|
open(
|
||||||
|
CreateEditViewModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import Button from "components/common/Button.svelte"
|
import Button from "components/common/Button.svelte"
|
||||||
import { store } from "builderStore"
|
export let apps
|
||||||
|
|
||||||
let errors = []
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
@ -12,11 +10,10 @@
|
||||||
class="logo"
|
class="logo"
|
||||||
alt="budibase logo" />
|
alt="budibase logo" />
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 style="margin-bottom: 20px">Choose an Application</h4>
|
<h4 style="margin-bottom: 20px">Choose an Application</h4>
|
||||||
{#each $store.apps as app}
|
{#each apps as app}
|
||||||
<a href={`#${app}`} class="app-link">{app}</a>
|
<a href={`/_builder/${app}`} class="app-link">{app}</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
||||||
<form class="uk-search uk-search-large">
|
<form on:submit|preventDefault class="uk-search uk-search-large">
|
||||||
<span uk-search-icon />
|
<span uk-search-icon />
|
||||||
<input
|
<input
|
||||||
class="uk-search-input"
|
class="uk-search-input"
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
import Dropdown from "components/common/Dropdown.svelte"
|
import Dropdown from "components/common/Dropdown.svelte"
|
||||||
import PlusButton from "components/common/PlusButton.svelte"
|
import PlusButton from "components/common/PlusButton.svelte"
|
||||||
import IconButton from "components/common/IconButton.svelte"
|
import IconButton from "components/common/IconButton.svelte"
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import EventEditorModal from "./EventEditorModal.svelte"
|
import EventEditorModal from "./EventEditorModal.svelte"
|
||||||
import HandlerSelector from "./HandlerSelector.svelte"
|
import HandlerSelector from "./HandlerSelector.svelte"
|
||||||
|
|
||||||
|
@ -64,7 +63,7 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<form class="uk-form-stacked form-root">
|
<form on:submit|preventDefault class="uk-form-stacked form-root">
|
||||||
{#each events as event, index}
|
{#each events as event, index}
|
||||||
{#if event.handlers.length > 0}
|
{#if event.handlers.length > 0}
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
<h3>{$store.currentPageName}</h3>
|
<h3>{$store.currentPageName}</h3>
|
||||||
|
|
||||||
<form class="uk-form-horizontal">
|
<form on:submit|preventDefault class="uk-form-horizontal">
|
||||||
<Textbox bind:text={title} label="Title" hasError={!title} />
|
<Textbox bind:text={title} label="Title" hasError={!title} />
|
||||||
<div class="help-text">
|
<div class="help-text">
|
||||||
The title of your page, displayed in the bowser tab
|
The title of your page, displayed in the bowser tab
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
||||||
<form class="uk-form-stacked form-root">
|
<form on:submit|preventDefault class="uk-form-stacked form-root">
|
||||||
{#if componentDef}
|
{#if componentDef}
|
||||||
{#each Object.entries(componentDef.props) as [prop_name, prop_def], index}
|
{#each Object.entries(componentDef.props) as [prop_name, prop_def], index}
|
||||||
<div class="prop-container">
|
<div class="prop-container">
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
import PagesList from "./PagesList.svelte"
|
import PagesList from "./PagesList.svelte"
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import IconButton from "components/common/IconButton.svelte"
|
import IconButton from "components/common/IconButton.svelte"
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
import NewScreen from "./NewScreen.svelte"
|
import NewScreen from "./NewScreen.svelte"
|
||||||
import CurrentItemPreview from "./CurrentItemPreview.svelte"
|
import CurrentItemPreview from "./CurrentItemPreview.svelte"
|
||||||
import SettingsView from "./SettingsView.svelte"
|
import SettingsView from "./SettingsView.svelte"
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
|
display: grid;
|
||||||
font-family: var(--fontnormal);
|
font-family: var(--fontnormal);
|
||||||
color: var(--secondary80);
|
color: var(--secondary80);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -1,10 +1,28 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { store } from "builderStore"
|
||||||
|
|
||||||
import { fade } from "svelte/transition"
|
import { fade } from "svelte/transition"
|
||||||
import { isActive, goto, url, context } from "@sveltech/routify"
|
import { isActive, goto, context } from "@sveltech/routify"
|
||||||
|
|
||||||
import { SettingsIcon, PreviewIcon } from "../../common/Icons/"
|
import { SettingsIcon, PreviewIcon } from "components/common/Icons/"
|
||||||
import IconButton from "../../common/IconButton.svelte"
|
import IconButton from "components/common/IconButton.svelte"
|
||||||
|
|
||||||
|
// Get Package and set store
|
||||||
|
export let application
|
||||||
|
|
||||||
|
let promise = getPackage()
|
||||||
|
|
||||||
|
async function getPackage() {
|
||||||
|
const res = await fetch(`/_builder/api/${application}/appPackage`)
|
||||||
|
const pkg = await res.json()
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
await store.setPackage(pkg)
|
||||||
|
return pkg
|
||||||
|
} else {
|
||||||
|
throw new Error(pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
$: ({ component } = $context)
|
$: ({ component } = $context)
|
||||||
$: list = component.parent.children.filter(child => child.isIndexable)
|
$: list = component.parent.children.filter(child => child.isIndexable)
|
||||||
</script>
|
</script>
|
||||||
|
@ -19,12 +37,12 @@
|
||||||
alt="budibase icon" />
|
alt="budibase icon" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- List is an array of subfolders in the application folder. -->
|
<!-- This gets all indexable subroutes and sticks them in the top nav. -->
|
||||||
{#each list as { path, prettyName, children, meta }}
|
{#each list as { path, prettyName, children, meta }}
|
||||||
<span
|
<span
|
||||||
class:active={$isActive(path)}
|
class:active={$isActive(path)}
|
||||||
class="topnavitem"
|
class="topnavitem"
|
||||||
on:click={() => $goto($url(path))}>
|
on:click={() => $goto(path)}>
|
||||||
{prettyName}
|
{prettyName}
|
||||||
</span>
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -34,9 +52,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="toprightnav">
|
<div class="toprightnav">
|
||||||
<span
|
<span
|
||||||
class:active={$isActive(`${component.parent.path}/settings`)}
|
class:active={$isActive(`/settings`)}
|
||||||
class="topnavitemright"
|
class="topnavitemright"
|
||||||
on:click={() => $goto(`${component.parent.path}/settings`)}>
|
on:click={() => $goto(`/settings`)}>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
|
@ -48,7 +66,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<slot />
|
{#await promise}
|
||||||
|
<!-- This should probably be some kind of loading state? -->
|
||||||
|
<div />
|
||||||
|
{:then}
|
||||||
|
<slot />
|
||||||
|
{/await}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import * as api from "components/database/ModelDataTable/api"
|
||||||
|
|
||||||
|
import BackendNav from "components/nav/BackendNav.svelte"
|
||||||
|
import SchemaManagementDrawer from "components/nav/SchemaManagementDrawer.svelte"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="root">
|
||||||
|
<div class="nav">
|
||||||
|
<BackendNav />
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div class="nav">
|
||||||
|
<SchemaManagementDrawer />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.root {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin: 20px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
overflow: auto;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
width: 275px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,4 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
import ButtonGroup from "components/common/ButtonGroup.svelte"
|
import ButtonGroup from "components/common/ButtonGroup.svelte"
|
||||||
import Button from "components/common/Button.svelte"
|
import Button from "components/common/Button.svelte"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
@ -8,39 +11,34 @@
|
||||||
getNewAccessLevel,
|
getNewAccessLevel,
|
||||||
} from "components/common/core"
|
} from "components/common/core"
|
||||||
import getIcon from "components/common/icon"
|
import getIcon from "components/common/icon"
|
||||||
import AccessLevelView from "./AccessLevelView.svelte"
|
import AccessLevelView from "components/accessLevels/AccessLevelView.svelte"
|
||||||
import Modal from "components/common/Modal.svelte"
|
|
||||||
|
|
||||||
let editingLevel = null
|
let editingLevel = null
|
||||||
let editingLevelIsNew = false
|
let editingLevelIsNew = false
|
||||||
$: {
|
|
||||||
if (editingLevel !== null) {
|
|
||||||
backendUiStore.actions.modals.show("ACCESS_LEVELS")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$: modalOpen = $backendUiStore.visibleModal === "ACCESS_LEVELS"
|
|
||||||
|
|
||||||
let allPermissions = []
|
let allPermissions = []
|
||||||
store.subscribe(db => {
|
store.subscribe(db => {
|
||||||
allPermissions = generateFullPermissions(db.hierarchy, db.actions)
|
allPermissions = generateFullPermissions(db.hierarchy, db.actions)
|
||||||
})
|
})
|
||||||
|
|
||||||
let onLevelEdit = level => {
|
const openModal = (level, newLevel) => {
|
||||||
editingLevel = level
|
editingLevel = level
|
||||||
editingLevelIsNew = false
|
editingLevelIsNew = newLevel
|
||||||
|
open(AccessLevelView, {
|
||||||
|
level: editingLevel,
|
||||||
|
allPermissions,
|
||||||
|
onFinished: onEditingFinished,
|
||||||
|
isNew: editingLevelIsNew,
|
||||||
|
allLevels: $store.accessLevels.levels,
|
||||||
|
hierarchy: $store.hierarchy,
|
||||||
|
actions: $store.actions,
|
||||||
|
close: close,
|
||||||
|
title: "Access Level",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let onLevelCancel = () => {
|
let cancel = () => {
|
||||||
editingAction = null
|
editingAction = null
|
||||||
}
|
close()
|
||||||
|
|
||||||
let onLevelDelete = level => {
|
|
||||||
store.deleteLevel(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
let createNewLevel = () => {
|
|
||||||
editingLevelIsNew = true
|
|
||||||
editingLevel = getNewAccessLevel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let onEditingFinished = level => {
|
let onEditingFinished = level => {
|
||||||
|
@ -48,7 +46,7 @@
|
||||||
store.saveLevel(level, editingLevelIsNew, editingLevel)
|
store.saveLevel(level, editingLevelIsNew, editingLevel)
|
||||||
}
|
}
|
||||||
editingLevel = null
|
editingLevel = null
|
||||||
backendUiStore.actions.modals.hide()
|
close()
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPermissionsString = perms => {
|
const getPermissionsString = perms => {
|
||||||
|
@ -58,7 +56,7 @@
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<ActionButton primary on:click={createNewLevel}>
|
<ActionButton primary on:click={() => openModal(getNewAccessLevel(), true)}>
|
||||||
Create New Access Level
|
Create New Access Level
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
@ -78,10 +76,10 @@
|
||||||
<td>{level.name}</td>
|
<td>{level.name}</td>
|
||||||
<td>{getPermissionsString(level.permissions)}</td>
|
<td>{getPermissionsString(level.permissions)}</td>
|
||||||
<td class="edit-button">
|
<td class="edit-button">
|
||||||
<span on:click={() => onLevelEdit(level)}>
|
<span on:click={() => openModal(level, false)}>
|
||||||
{@html getIcon('edit')}
|
{@html getIcon('edit')}
|
||||||
</span>
|
</span>
|
||||||
<span on:click={() => onLevelDelete(level)}>
|
<span on:click={() => store.deleteLevel(level)}>
|
||||||
{@html getIcon('trash')}
|
{@html getIcon('trash')}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
@ -91,20 +89,6 @@
|
||||||
</table>
|
</table>
|
||||||
{:else}(no actions added){/if}
|
{:else}(no actions added){/if}
|
||||||
|
|
||||||
<Modal
|
|
||||||
onClosed={backendUiStore.actions.modals.hide}
|
|
||||||
bind:isOpen={modalOpen}
|
|
||||||
title={modalOpen ? 'Edit Access Level' : 'Create Access Level'}>
|
|
||||||
<AccessLevelView
|
|
||||||
level={editingLevel}
|
|
||||||
{allPermissions}
|
|
||||||
onFinished={onEditingFinished}
|
|
||||||
isNew={editingLevelIsNew}
|
|
||||||
allLevels={$store.accessLevels.levels}
|
|
||||||
hierarchy={$store.hierarchy}
|
|
||||||
actions={$store.actions} />
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import ModelDataTable from "components/database/ModelDataTable"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
import * as api from "components/database/ModelDataTable/api"
|
||||||
|
import { CreateEditRecordModal } from "components/database/ModelDataTable/modals"
|
||||||
|
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
const createNewRecord = () => {
|
||||||
|
selectedRecord = null
|
||||||
|
open(
|
||||||
|
CreateEditRecordModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
record: selectedRecord,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export let selectedDatabase
|
||||||
|
|
||||||
|
let selectedRecord
|
||||||
|
|
||||||
|
async function selectRecord(record) {
|
||||||
|
selectedRecord = await api.loadRecord(record.key, {
|
||||||
|
appname: $store.appname,
|
||||||
|
instanceId: selectedDatabase,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$: breadcrumbs = $backendUiStore.breadcrumbs.join(" / ")
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="database-actions">
|
||||||
|
<div class="budibase__label--big">{breadcrumbs}</div>
|
||||||
|
{#if $backendUiStore.selectedDatabase.id}
|
||||||
|
<ActionButton primary on:click={createNewRecord}>
|
||||||
|
Create new record
|
||||||
|
</ActionButton>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if $backendUiStore.selectedDatabase.id}
|
||||||
|
<ModelDataTable {selectRecord} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.database-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<script>
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import { goto } from "@sveltech/routify"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
|
$: instances = $store.appInstances
|
||||||
|
$: views = $store.hierarchy.indexes
|
||||||
|
|
||||||
|
async function selectDatabase(database) {
|
||||||
|
backendUiStore.actions.records.select(null)
|
||||||
|
backendUiStore.actions.views.select(views[0])
|
||||||
|
backendUiStore.actions.database.select(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if ($store.appInstances.length > 0) {
|
||||||
|
await selectDatabase($store.appInstances[0])
|
||||||
|
$goto(`./${$backendUiStore.selectedDatabase.id}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="root">
|
||||||
|
<div class="node-view">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.root {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-view {
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<script>
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import { goto } from "@sveltech/routify"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
|
$: instances = $store.appInstances
|
||||||
|
$: views = $store.hierarchy.indexes
|
||||||
|
|
||||||
|
async function selectDatabase(database) {
|
||||||
|
backendUiStore.actions.records.select(null)
|
||||||
|
backendUiStore.actions.views.select(views[0])
|
||||||
|
backendUiStore.actions.database.select(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if ($store.appInstances.length > 0) {
|
||||||
|
await selectDatabase($store.appInstances[0])
|
||||||
|
$goto(`../${$backendUiStore.selectedDatabase.id}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
Please select a database
|
|
@ -3,4 +3,4 @@
|
||||||
$goto("../database")
|
$goto("../database")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- routify:options $index=false -->
|
<!-- routify:options index=false -->
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script>
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import { goto } from "@sveltech/routify"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
|
$: instances = $store.appInstances
|
||||||
|
$: views = $store.hierarchy.indexes
|
||||||
|
|
||||||
|
async function selectDatabase(database) {
|
||||||
|
backendUiStore.actions.records.select(null)
|
||||||
|
backendUiStore.actions.views.select(views[0])
|
||||||
|
backendUiStore.actions.database.select(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if ($store.appInstances.length > 0 && !$backendUiStore.database) {
|
||||||
|
await selectDatabase($store.appInstances[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot />
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
import UserInterfaceRoot from "components/userInterface/UserInterfaceRoot.svelte"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<UserInterfaceRoot />
|
|
@ -3,4 +3,4 @@
|
||||||
$goto("../backend")
|
$goto("../backend")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- routify:options $index=false -->
|
<!-- routify:options index=false -->
|
|
@ -0,0 +1,2 @@
|
||||||
|
<!-- routify:options index=false -->
|
||||||
|
<slot />
|
|
@ -1,48 +0,0 @@
|
||||||
<script>
|
|
||||||
import BackendNav from "../../../nav/BackendNav.svelte"
|
|
||||||
import SchemaManagementDrawer from "../../../nav/SchemaManagementDrawer.svelte"
|
|
||||||
import Database from "../../../database/DatabaseRoot.svelte"
|
|
||||||
import UserInterface from "../../../userInterface/UserInterfaceRoot.svelte"
|
|
||||||
import ActionsAndTriggers from "../../../actionsAndTriggers/ActionsAndTriggersRoot.svelte"
|
|
||||||
import AccessLevels from "../../../accessLevels/AccessLevelsRoot.svelte"
|
|
||||||
import ComingSoon from "../../../common/ComingSoon.svelte"
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="root">
|
|
||||||
<div class="nav">
|
|
||||||
<BackendNav />
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<!-- {#if $backendUiStore.leftNavItem === 'DATABASE'}
|
|
||||||
<Database />
|
|
||||||
{:else if $backendUiStore.leftNavItem === 'ACTIONS'}
|
|
||||||
<ActionsAndTriggers />
|
|
||||||
{:else if $backendUiStore.leftNavItem === 'ACCESS_LEVELS'}
|
|
||||||
<AccessLevels />
|
|
||||||
{/if} -->
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
<div class="nav">
|
|
||||||
<!-- <SchemaManagementDrawer /> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
margin: 80px 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav {
|
|
||||||
overflow: auto;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
width: 300px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,134 +0,0 @@
|
||||||
<script>
|
|
||||||
import getIcon from "../../../../common/icon"
|
|
||||||
import Button from "../../../../common/Button.svelte"
|
|
||||||
import ActionButton from "../../../../common/ActionButton.svelte"
|
|
||||||
import ButtonGroup from "../../../../common/ButtonGroup.svelte"
|
|
||||||
import Actions from "../../../../actionsAndTriggers/Actions.svelte"
|
|
||||||
import Triggers from "../../../../actionsAndTriggers/Triggers.svelte"
|
|
||||||
import { getNewAction, getNewTrigger } from "../../../../common/core"
|
|
||||||
|
|
||||||
let editingAction = null
|
|
||||||
let editingActionIsNew = true
|
|
||||||
let editingTrigger = null
|
|
||||||
let editingTriggerIsNew = true
|
|
||||||
|
|
||||||
let getDefaultOptionsHtml = defaultOptions =>
|
|
||||||
pipe(
|
|
||||||
defaultOptions,
|
|
||||||
[
|
|
||||||
keys,
|
|
||||||
map(
|
|
||||||
k =>
|
|
||||||
`<span style="color:var(--slate)">${k}: </span>${JSON.parse(
|
|
||||||
typeOptions[k]
|
|
||||||
)}`
|
|
||||||
),
|
|
||||||
join("<br>"),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
let onActionEdit = action => {
|
|
||||||
editingAction = action
|
|
||||||
editingActionIsNew = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let newAction = () => {
|
|
||||||
editingAction = getNewAction()
|
|
||||||
editingActionIsNew = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let onActionDelete = action => {
|
|
||||||
store.deleteAction(action)
|
|
||||||
}
|
|
||||||
|
|
||||||
let deleteTrigger = () => {}
|
|
||||||
|
|
||||||
let editTrigger = trigger => {
|
|
||||||
editingTrigger = trigger
|
|
||||||
editingTriggerIsNew = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let newTrigger = () => {
|
|
||||||
editingTrigger = getNewTrigger()
|
|
||||||
editingTriggerIsNew = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let onActionSave = action => {
|
|
||||||
store.saveAction(action, editingActionIsNew, editingAction)
|
|
||||||
|
|
||||||
editingAction = null
|
|
||||||
}
|
|
||||||
|
|
||||||
let onActionCancel = () => {
|
|
||||||
editingAction = null
|
|
||||||
}
|
|
||||||
|
|
||||||
let onTriggerSave = trigger => {
|
|
||||||
store.saveTrigger(trigger, editingTriggerIsNew, editingTrigger)
|
|
||||||
|
|
||||||
editingTrigger = null
|
|
||||||
}
|
|
||||||
|
|
||||||
let onTriggerCancel = () => {
|
|
||||||
editingTrigger = null
|
|
||||||
}
|
|
||||||
|
|
||||||
let onTriggerEdit = trigger => {
|
|
||||||
editingTrigger = trigger
|
|
||||||
editingTriggerIsNew = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let onTriggerDelete = trigger => {
|
|
||||||
store.deleteTrigger(trigger)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="root">
|
|
||||||
<div class="actions-header">
|
|
||||||
<ButtonGroup>
|
|
||||||
<ActionButton color="secondary" grouped on:click={newAction}>
|
|
||||||
Create New Action
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton color="tertiary" grouped on:click={newTrigger}>
|
|
||||||
Create New Trigger
|
|
||||||
</ActionButton>
|
|
||||||
</ButtonGroup>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="node-view">
|
|
||||||
<Actions
|
|
||||||
{editingActionIsNew}
|
|
||||||
{editingAction}
|
|
||||||
{onActionEdit}
|
|
||||||
{onActionDelete}
|
|
||||||
{onActionSave}
|
|
||||||
{onActionCancel} />
|
|
||||||
|
|
||||||
<Triggers
|
|
||||||
{editingTriggerIsNew}
|
|
||||||
{editingTrigger}
|
|
||||||
{onTriggerEdit}
|
|
||||||
{onTriggerDelete}
|
|
||||||
{onTriggerSave}
|
|
||||||
{onTriggerCancel} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions-header {
|
|
||||||
flex: 0 1 auto;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-view {
|
|
||||||
overflow-y: auto;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,96 +0,0 @@
|
||||||
<script>
|
|
||||||
import ModelView from "../../../../database/ModelView.svelte"
|
|
||||||
import IndexView from "../../../../database/IndexView.svelte"
|
|
||||||
import ModelDataTable from "../../../../database/ModelDataTable"
|
|
||||||
import ActionsHeader from "../../../../database/ActionsHeader.svelte"
|
|
||||||
import { store, backendUiStore } from "../../../../builderStore"
|
|
||||||
import getIcon from "../../../../common/icon"
|
|
||||||
import DropdownButton from "../../../../common/DropdownButton.svelte"
|
|
||||||
import ActionButton from "../../../../common/ActionButton.svelte"
|
|
||||||
import Modal from "../../../../common/Modal.svelte"
|
|
||||||
import {
|
|
||||||
CreateEditRecordModal,
|
|
||||||
CreateEditModelModal,
|
|
||||||
CreateEditViewModal,
|
|
||||||
CreateDatabaseModal,
|
|
||||||
DeleteRecordModal,
|
|
||||||
CreateUserModal,
|
|
||||||
} from "../../../../database/ModelDataTable/modals"
|
|
||||||
|
|
||||||
let selectedRecord
|
|
||||||
|
|
||||||
function selectRecord(record) {
|
|
||||||
selectedRecord = record
|
|
||||||
}
|
|
||||||
|
|
||||||
function onClosed() {
|
|
||||||
backendUiStore.actions.modals.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
$: recordOpen = $backendUiStore.visibleModal === "RECORD"
|
|
||||||
$: modelOpen = $backendUiStore.visibleModal === "MODEL"
|
|
||||||
$: viewOpen = $backendUiStore.visibleModal === "VIEW"
|
|
||||||
$: databaseOpen = $backendUiStore.visibleModal === "DATABASE"
|
|
||||||
$: deleteRecordOpen = $backendUiStore.visibleModal === "DELETE_RECORD"
|
|
||||||
$: userOpen = $backendUiStore.visibleModal === "USER"
|
|
||||||
$: breadcrumbs = $backendUiStore.breadcrumbs.join(" / ")
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Modal isOpen={!!$backendUiStore.visibleModal} {onClosed}>
|
|
||||||
{#if recordOpen}
|
|
||||||
<CreateEditRecordModal record={selectedRecord} {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if modelOpen}
|
|
||||||
<CreateEditModelModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if viewOpen}
|
|
||||||
<CreateEditViewModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if databaseOpen}
|
|
||||||
<CreateDatabaseModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if deleteRecordOpen}
|
|
||||||
<DeleteRecordModal record={selectedRecord} {onClosed} />
|
|
||||||
{/if}
|
|
||||||
{#if userOpen}
|
|
||||||
<CreateUserModal {onClosed} />
|
|
||||||
{/if}
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<div class="root">
|
|
||||||
<div class="node-view">
|
|
||||||
<div class="database-actions">
|
|
||||||
<div class="budibase__label--big">{breadcrumbs}</div>
|
|
||||||
{#if $backendUiStore.selectedDatabase.id}
|
|
||||||
<ActionButton
|
|
||||||
primary
|
|
||||||
on:click={() => {
|
|
||||||
selectedRecord = null
|
|
||||||
backendUiStore.actions.modals.show('RECORD')
|
|
||||||
}}>
|
|
||||||
Create new record
|
|
||||||
</ActionButton>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{#if $backendUiStore.selectedDatabase.id}
|
|
||||||
<ModelDataTable {selectRecord} />
|
|
||||||
{:else}Please select a database{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-view {
|
|
||||||
overflow-y: auto;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.database-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1 +0,0 @@
|
||||||
<slot />
|
|
|
@ -1,2 +0,0 @@
|
||||||
<!-- routify:options $index=false -->
|
|
||||||
<slot />
|
|
|
@ -1,10 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import AppList from "../AppList.svelte"
|
import AppList from "components/start/AppList.svelte"
|
||||||
import PackageRoot from "../PackageRoot.svelte"
|
|
||||||
import Settings from "../Settings.svelte"
|
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import IconButton from "../common/IconButton.svelte"
|
import IconButton from "components/common/IconButton.svelte"
|
||||||
import Spinner from "../common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
|
|
||||||
let promise = getApps()
|
let promise = getApps()
|
||||||
|
|
||||||
|
@ -21,7 +19,6 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
|
||||||
{#await promise}
|
{#await promise}
|
||||||
<div class="spinner-container">
|
<div class="spinner-container">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
|
|
|
@ -3,6 +3,7 @@ const StatusCodes = require("../../utilities/statusCodes")
|
||||||
const {
|
const {
|
||||||
getPackageForBuilder,
|
getPackageForBuilder,
|
||||||
getApps,
|
getApps,
|
||||||
|
saveBackend
|
||||||
} = require("../../utilities/builder")
|
} = require("../../utilities/builder")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ run the budibase server and builder in dev mode (i.e. with hot reloading):
|
||||||
|
|
||||||
1. Open a new console
|
1. Open a new console
|
||||||
2. `yarn dev` (from root)
|
2. `yarn dev` (from root)
|
||||||
3. Access the builder on http://localhost:3000
|
3. Access the builder on http://localhost:4001/_builder/
|
||||||
|
|
||||||
This will enable watch mode for both the client AND the server.
|
This will enable watch mode for both the client AND the server.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue