forked from tsai/budibase
19 changed files with 580 additions and 36 deletions
@ -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 = {} |
|||
@ -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> |
|||
Loading…
Reference in new issue