structuring new backend UI
This commit is contained in:
parent
624a5c5d81
commit
48f6ac2b98
|
@ -39,7 +39,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@beyonk/svelte-notifications": "^2.0.3",
|
"@beyonk/svelte-notifications": "^2.0.3",
|
||||||
"@budibase/bbui": "^1.1.1",
|
"@budibase/bbui": "^1.4.1",
|
||||||
"@budibase/client": "^0.0.32",
|
"@budibase/client": "^0.0.32",
|
||||||
"@nx-js/compiler-util": "^2.0.0",
|
"@nx-js/compiler-util": "^2.0.0",
|
||||||
"codemirror": "^5.51.0",
|
"codemirror": "^5.51.0",
|
||||||
|
|
|
@ -153,6 +153,10 @@ export default {
|
||||||
find: "builderStore",
|
find: "builderStore",
|
||||||
replacement: path.resolve(projectRootDir, "src/builderStore"),
|
replacement: path.resolve(projectRootDir, "src/builderStore"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
find: "constants",
|
||||||
|
replacement: path.resolve(projectRootDir, "src/constants"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
customResolver,
|
customResolver,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -39,18 +39,6 @@ export const getBackendUiStore = () => {
|
||||||
state.views = views
|
state.views = views
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
/** TODO: DEMO SOLUTION**/
|
|
||||||
if (!models || models.length === 0) {
|
|
||||||
const { open, close } = getContext("simple-modal")
|
|
||||||
open(
|
|
||||||
CreateEditModelModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/** DEMO SOLUTION END **/
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
records: {
|
records: {
|
||||||
|
@ -71,6 +59,10 @@ export const getBackendUiStore = () => {
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
models: {
|
models: {
|
||||||
|
select: model => store.update(state => {
|
||||||
|
state.selectedModel = model;
|
||||||
|
return state;
|
||||||
|
}),
|
||||||
create: model =>
|
create: model =>
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.models.push(model)
|
state.models.push(model)
|
||||||
|
@ -78,7 +70,7 @@ export const getBackendUiStore = () => {
|
||||||
state.selectedModel = model
|
state.selectedModel = model
|
||||||
state.selectedView = `all_${model._id}`
|
state.selectedView = `all_${model._id}`
|
||||||
return state
|
return state
|
||||||
}),
|
})
|
||||||
},
|
},
|
||||||
views: {
|
views: {
|
||||||
select: view =>
|
select: view =>
|
||||||
|
|
|
@ -20,12 +20,6 @@
|
||||||
$: modelFields = model.schema ? Object.entries(model.schema) : []
|
$: modelFields = model.schema ? Object.entries(model.schema) : []
|
||||||
$: instanceId = $backendUiStore.selectedDatabase._id
|
$: instanceId = $backendUiStore.selectedDatabase._id
|
||||||
|
|
||||||
function editField() {}
|
|
||||||
|
|
||||||
function deleteField() {}
|
|
||||||
|
|
||||||
function onFinishedFieldEdit() {}
|
|
||||||
|
|
||||||
async function saveModel() {
|
async function saveModel() {
|
||||||
const SAVE_MODEL_URL = `/api/${instanceId}/models`
|
const SAVE_MODEL_URL = `/api/${instanceId}/models`
|
||||||
const response = await api.post(SAVE_MODEL_URL, model)
|
const response = await api.post(SAVE_MODEL_URL, model)
|
||||||
|
@ -94,7 +88,6 @@
|
||||||
{:else}
|
{:else}
|
||||||
<FieldView
|
<FieldView
|
||||||
field={fieldToEdit}
|
field={fieldToEdit}
|
||||||
onFinished={onFinishedFieldEdit}
|
|
||||||
schema={model.schema}
|
schema={model.schema}
|
||||||
goBack={() => (showFieldView = false)} />
|
goBack={() => (showFieldView = false)} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -31,14 +31,6 @@
|
||||||
class:selected={$backendUiStore.selectedView === `all_${node._id}`}>
|
class:selected={$backendUiStore.selectedView === `all_${node._id}`}>
|
||||||
<i class={ICON_MAP[type]} />
|
<i class={ICON_MAP[type]} />
|
||||||
<span style="margin-left: 1rem">{node.name}</span>
|
<span style="margin-left: 1rem">{node.name}</span>
|
||||||
<!-- <i
|
|
||||||
class="ri-edit-line hoverable"
|
|
||||||
on:click={editModel}
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
class="ri-delete-bin-7-line hoverable"
|
|
||||||
on:click={deleteModel}
|
|
||||||
/> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<script>
|
||||||
|
export let title
|
||||||
|
export let icon
|
||||||
|
|
||||||
|
export let primary
|
||||||
|
export let secondary
|
||||||
|
export let tertiary
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div on:click class:primary class:secondary class:tertiary>
|
||||||
|
<i class={icon} />
|
||||||
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
height: 90px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--ink);
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
background: var(--ink);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
background: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tertiary {
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,79 @@
|
||||||
|
<script>
|
||||||
|
import * as blockDefinitions from "constants/backend"
|
||||||
|
import Block from "./Block.svelte"
|
||||||
|
|
||||||
|
console.log(blockDefinitions)
|
||||||
|
|
||||||
|
const HEADINGS = [
|
||||||
|
{
|
||||||
|
title: "Fields",
|
||||||
|
key: "FIELDS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Blocks",
|
||||||
|
key: "BLOCKS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Table",
|
||||||
|
key: "TABLES",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let selectedTab = "FIELDS"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
{#each HEADINGS as tab}
|
||||||
|
<span
|
||||||
|
class:selected={selectedTab === tab.key}
|
||||||
|
on:click={() => (selectedTab = tab.key)}>
|
||||||
|
{tab.title}
|
||||||
|
</span>
|
||||||
|
{/each}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="block-grid">
|
||||||
|
{#each Object.values(blockDefinitions[selectedTab]) as blockDefinition}
|
||||||
|
<Block
|
||||||
|
primary={true}
|
||||||
|
secondary={false}
|
||||||
|
tertiary={false}
|
||||||
|
title={blockDefinition.name}
|
||||||
|
icon={blockDefinition.icon} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-right: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--ink-lighter);
|
||||||
|
font-size: 14px;
|
||||||
|
background: var(--light-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
span:hover {
|
||||||
|
background: var(--secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background: var(--secondary);
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-grid {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,46 @@
|
||||||
|
<script>
|
||||||
|
export let icon
|
||||||
|
export let className
|
||||||
|
export let title
|
||||||
|
export let selected
|
||||||
|
export let indented
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class:selected on:click class={className}>
|
||||||
|
<i class:indented class={icon} />
|
||||||
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.indented {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
padding: 0 10px 0 10px;
|
||||||
|
width: 260px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
transition: 0.3s background-color;
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
div:hover {
|
||||||
|
background-color: var(--secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: var(--dark-grey);
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,90 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import { Switcher } from "@budibase/bbui"
|
||||||
|
import { goto } from "@sveltech/routify"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import BlockNavigator from "./BlockNavigator.svelte";
|
||||||
|
import SchemaManagementDrawer from "../SchemaManagementDrawer.svelte"
|
||||||
|
import HierarchyRow from "../HierarchyRow.svelte"
|
||||||
|
import ListItem from "./ListItem.svelte"
|
||||||
|
import { Button } from "@budibase/bbui"
|
||||||
|
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
const HEADINGS = [
|
||||||
|
{
|
||||||
|
title: "Navigate",
|
||||||
|
key: "NAVIGATE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Add",
|
||||||
|
key: "ADD",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let selectedTab = "NAVIGATE"
|
||||||
|
|
||||||
|
function selectModel(model) {
|
||||||
|
backendUiStore.actions.models.select(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectField() {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="items-root">
|
||||||
|
{#if $backendUiStore.selectedDatabase._id}
|
||||||
|
<div class="hierarchy">
|
||||||
|
<div class="components-list-container">
|
||||||
|
<Switcher headings={HEADINGS} bind:value={selectedTab}>
|
||||||
|
{#if selectedTab === 'NAVIGATE'}
|
||||||
|
<Button
|
||||||
|
secondary
|
||||||
|
wide
|
||||||
|
on:click={() => $goto(`./database/${$backendUiStore.selectedDatabase._id}/newmodel`)}>
|
||||||
|
Create New Model
|
||||||
|
</Button>
|
||||||
|
<div class="hierarchy-items-container">
|
||||||
|
{#each $backendUiStore.models as model}
|
||||||
|
<ListItem
|
||||||
|
selected={model._id === $backendUiStore.selectedModel._id}
|
||||||
|
title={model.name}
|
||||||
|
icon="ri-table-fill"
|
||||||
|
on:click={() => selectModel(model)} />
|
||||||
|
{#each Object.keys(model.schema) as field}
|
||||||
|
<ListItem
|
||||||
|
indented
|
||||||
|
icon="ri-layout-column-fill"
|
||||||
|
title={field}
|
||||||
|
on:click={() => selectField(model.schema[field])} />
|
||||||
|
{/each}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{:else if selectedTab === 'ADD'}
|
||||||
|
<BlockNavigator />
|
||||||
|
{/if}
|
||||||
|
</Switcher>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.items-root {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--white);
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hierarchy {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hierarchy-items-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,111 @@
|
||||||
|
<script>
|
||||||
|
import { getContext, onMount } from "svelte"
|
||||||
|
import { Button, Switcher } from "@budibase/bbui"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import HierarchyRow from "./HierarchyRow.svelte"
|
||||||
|
import NavItem from "./NavItem.svelte"
|
||||||
|
import getIcon from "components/common/icon"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
import {
|
||||||
|
CreateEditModelModal,
|
||||||
|
CreateEditViewModal,
|
||||||
|
} from "components/database/ModelDataTable/modals"
|
||||||
|
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
const ITEMS = [
|
||||||
|
{
|
||||||
|
title: "Setup",
|
||||||
|
key: "SETUP",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Filter",
|
||||||
|
key: "FILTER",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Delete",
|
||||||
|
key: "DELETE",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let selectedTab = "SETUP"
|
||||||
|
let modelName = $backendUiStore.selectedModel.name
|
||||||
|
let edited
|
||||||
|
|
||||||
|
$: if (modelName) {
|
||||||
|
edited = modelName !== $backendUiStore.selectedModel.name
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteModel() {
|
||||||
|
const modelToDelete = $backendUiStore.selectedModel
|
||||||
|
const DELETE_MODEL_URL = `/api/${instanceId}/models/${modelToDelete._id}/${modelToDelete._rev}`
|
||||||
|
const response = await api.delete(DELETE_MODEL_URL)
|
||||||
|
backendUiStore.update(state => {
|
||||||
|
state.models = state.models.filter(
|
||||||
|
model => model._id !== modelToDelete._id
|
||||||
|
)
|
||||||
|
state.selectedView = {}
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectView(view) {
|
||||||
|
backendUiStore.update(state => {
|
||||||
|
state.selectedView = view.name
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="items-root">
|
||||||
|
<Switcher headings={ITEMS} bind:value={selectedTab}>
|
||||||
|
{#if selectedTab === 'SETUP'}
|
||||||
|
<div class="titled-input">
|
||||||
|
<header>Name</header>
|
||||||
|
<input type="text" class="budibase__input" bind:value={modelName} />
|
||||||
|
</div>
|
||||||
|
<div class="titled-input">
|
||||||
|
<header>Import Data</header>
|
||||||
|
<Button wide secondary>Import CSV</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={!edited}
|
||||||
|
attention={edited}
|
||||||
|
wide
|
||||||
|
on:click={() => alert('Clicked!')}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
{:else if selectedTab === 'DELETE'}
|
||||||
|
<div class="titled-input">
|
||||||
|
<header>Danger Zone</header>
|
||||||
|
<Button error wide on:click={deleteModel}>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Switcher>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.items-root {
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.titled-input {
|
||||||
|
padding: 20px;
|
||||||
|
background: var(--light-grey);
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titled-input header {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,101 @@
|
||||||
|
const FIELD_TYPES = ["string", "number", "boolean"]
|
||||||
|
|
||||||
|
export const FIELDS = {
|
||||||
|
PLAIN_TEXT: {
|
||||||
|
name: "Plain Text",
|
||||||
|
icon: "ri-text",
|
||||||
|
definition: {
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NUMBER: {
|
||||||
|
name: "Number",
|
||||||
|
icon: "ri-number-1",
|
||||||
|
definition: {
|
||||||
|
type: "number",
|
||||||
|
constraints: {
|
||||||
|
type: "number",
|
||||||
|
presence: false,
|
||||||
|
numericality: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BOOLEAN: {
|
||||||
|
name: "True/False",
|
||||||
|
icon: "ri-toggle-line",
|
||||||
|
definition: {
|
||||||
|
type: "boolean",
|
||||||
|
constraints: {
|
||||||
|
type: "boolean",
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OPTIONS: {
|
||||||
|
name: "Options",
|
||||||
|
icon: "ri-list-check-2",
|
||||||
|
definition: {
|
||||||
|
type: "options",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DATETIME: {
|
||||||
|
name: "Date/Time",
|
||||||
|
icon: "ri-calendar-event-fill",
|
||||||
|
definition: {
|
||||||
|
type: "date",
|
||||||
|
constraints: {
|
||||||
|
type: "date",
|
||||||
|
datetime: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
IMAGE: {
|
||||||
|
name: "Image",
|
||||||
|
icon: "ri-image-line",
|
||||||
|
definition: {
|
||||||
|
type: "image",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FILE: {
|
||||||
|
name: "Image",
|
||||||
|
icon: "ri-file-line",
|
||||||
|
definition: {
|
||||||
|
type: "file",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DATA_LINK: {
|
||||||
|
name: "Data Links",
|
||||||
|
icon: "ri-link",
|
||||||
|
definition: {
|
||||||
|
type: "link",
|
||||||
|
modelId: null,
|
||||||
|
constraints: {
|
||||||
|
type: "array",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BLOCKS = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TABLES = {}
|
|
@ -3,19 +3,19 @@
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import * as api from "components/database/ModelDataTable/api"
|
import * as api from "components/database/ModelDataTable/api"
|
||||||
|
|
||||||
import BackendNav from "components/nav/BackendNav.svelte"
|
import ModelNavigator from "components/nav/ModelNavigator/ModelNavigator.svelte"
|
||||||
import SchemaManagementDrawer from "components/nav/SchemaManagementDrawer.svelte"
|
import ModelSetupNav from "components/nav/ModelSetupNav.svelte"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<BackendNav />
|
<ModelNavigator />
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<SchemaManagementDrawer />
|
<ModelSetupNav />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<script>
|
||||||
|
export let title
|
||||||
|
export let icon
|
||||||
|
|
||||||
|
export let primary
|
||||||
|
export let secondary
|
||||||
|
export let tertiary
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- TODO: Move to bbui -->
|
||||||
|
<div on:click class:primary class:secondary class:tertiary>
|
||||||
|
<i class={icon} />
|
||||||
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
width: 120px;
|
||||||
|
height: 90px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--ink);
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
background: var(--ink);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
background: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tertiary {
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<script>
|
||||||
|
import { FIELDS } from "constants/backend";
|
||||||
|
import Block from "./Block.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<h2>Create New Table</h2>
|
||||||
|
<span>Before you can view your table, you need to set it up.</span>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="block-row">
|
||||||
|
<h4>Fields</h4>
|
||||||
|
<div class="blocks">
|
||||||
|
{#each Object.values(FIELDS) as field}
|
||||||
|
<Block primary title={field.name} icon={field.icon} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- TODO: More block rows -->
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-row {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-row .blocks {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
grid-gap: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -110,7 +110,7 @@ describe("/models", () => {
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
delete testModel._rev
|
delete testModel._rev
|
||||||
})
|
});
|
||||||
|
|
||||||
it("returns a success response when a model is deleted.", async done => {
|
it("returns a success response when a model is deleted.", async done => {
|
||||||
request
|
request
|
||||||
|
|
|
@ -41,7 +41,7 @@ const screenPath = (appPath, pageName, name) =>
|
||||||
|
|
||||||
module.exports.saveScreen = async (config, appname, pagename, screen) => {
|
module.exports.saveScreen = async (config, appname, pagename, screen) => {
|
||||||
const appPath = appPackageFolder(config, appname)
|
const appPath = appPackageFolder(config, appname)
|
||||||
const compPath = screenPath(appPath, pagename, screen.name)
|
const compPath = screenPath(appPath, pagename, screen.props._instanceName)
|
||||||
await ensureDir(dirname(compPath))
|
await ensureDir(dirname(compPath))
|
||||||
if (screen._css) {
|
if (screen._css) {
|
||||||
delete screen._css
|
delete screen._css
|
||||||
|
|
Loading…
Reference in New Issue