forked from tsai/budibase
committed by
GitHub
180 changed files with 3724 additions and 6300 deletions
@ -0,0 +1,126 @@ |
|||
<script> |
|||
export let width = "100" |
|||
export let height = "100" |
|||
</script> |
|||
|
|||
<svg |
|||
version="1.1" |
|||
id="Layer_1" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
xmlns:xlink="http://www.w3.org/1999/xlink" |
|||
x="0px" |
|||
y="0px" |
|||
viewBox="0 0 48 48" |
|||
style="enable-background:new 0 0 48 48;" |
|||
xml:space="preserve" |
|||
{height} |
|||
{width} |
|||
> |
|||
<style type="text/css"> |
|||
.st0 { |
|||
fill: #393c44; |
|||
} |
|||
.st1 { |
|||
fill: #ffffff; |
|||
} |
|||
.st2 { |
|||
fill: #4285f4; |
|||
} |
|||
</style> |
|||
<rect x="-152.17" y="-24.17" class="st0" width="96.17" height="96.17" /> |
|||
<path |
|||
class="st1" |
|||
d="M-83.19,48h-41.79c-1.76,0-3.19-1.43-3.19-3.19V3.02c0-1.76,1.43-3.19,3.19-3.19h41.79 |
|||
c1.76,0,3.19,1.43,3.19,3.19v41.79C-80,46.57-81.43,48-83.19,48z" |
|||
/> |
|||
<g> |
|||
<g> |
|||
<path |
|||
class="st0" |
|||
d="M-99.62,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57 |
|||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35 |
|||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35h-4.89V12.57H-99.62z |
|||
M-93.46,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69 |
|||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01 |
|||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68 |
|||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1 |
|||
C-93.55,28.92-93.46,28.52-93.46,28.11z" |
|||
/> |
|||
</g> |
|||
<g> |
|||
<path |
|||
class="st0" |
|||
d="M-114.76,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58 |
|||
c0.86,0.39,1.59,0.91,2.19,1.57c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89 |
|||
c-0.35,0.9-0.84,1.68-1.47,2.35c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35 |
|||
h-4.89V12.57H-114.76z M-108.6,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69 |
|||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01 |
|||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68 |
|||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1 |
|||
C-108.68,28.92-108.6,28.52-108.6,28.11z" |
|||
/> |
|||
</g> |
|||
</g> |
|||
<path |
|||
class="st2" |
|||
d="M44.81,159H3.02c-1.76,0-3.19-1.43-3.19-3.19v-41.79c0-1.76,1.43-3.19,3.19-3.19h41.79 |
|||
c1.76,0,3.19,1.43,3.19,3.19v41.79C48,157.57,46.57,159,44.81,159z" |
|||
/> |
|||
<g> |
|||
<g> |
|||
<path |
|||
class="st1" |
|||
d="M28.38,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57 |
|||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35 |
|||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146h-4.89v-22.43H28.38z |
|||
M34.54,139.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69 |
|||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01 |
|||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68 |
|||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1 |
|||
C34.45,139.92,34.54,139.52,34.54,139.11z" |
|||
/> |
|||
</g> |
|||
<g> |
|||
<path |
|||
class="st1" |
|||
d="M13.24,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57 |
|||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35 |
|||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146H8.35v-22.43H13.24z M19.4,139.11 |
|||
c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69c-0.38-0.17-0.79-0.26-1.24-0.26 |
|||
c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01c-0.17,0.39-0.26,0.8-0.26,1.23 |
|||
c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68c0.39,0.17,0.8,0.26,1.23,0.26 |
|||
c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1C19.32,139.92,19.4,139.52,19.4,139.11z" |
|||
/> |
|||
</g> |
|||
</g> |
|||
<g> |
|||
<path |
|||
class="st0" |
|||
d="M44,48H4c-2.21,0-4-1.79-4-4V4c0-2.21,1.79-4,4-4h40c2.21,0,4,1.79,4,4v40C48,46.21,46.21,48,44,48z" |
|||
/> |
|||
<g> |
|||
<path |
|||
class="st1" |
|||
d="M28.48,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65 |
|||
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47 |
|||
c-0.64,0.7-1.4,1.25-2.28,1.66C34.8,35.8,33.86,36,32.84,36c-1.84,0-3.3-0.69-4.37-2.07v1.62h-5V12H28.48z M34.78,28.31 |
|||
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27 |
|||
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29 |
|||
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27 |
|||
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C34.69,29.16,34.78,28.75,34.78,28.31z" |
|||
/> |
|||
</g> |
|||
<g> |
|||
<path |
|||
class="st1" |
|||
d="M13,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65 |
|||
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47 |
|||
c-0.64,0.7-1.4,1.25-2.28,1.66C19.32,35.8,18.38,36,17.37,36c-1.84,0-3.3-0.69-4.37-2.07v1.62H8V12H13z M19.3,28.31 |
|||
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27 |
|||
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29 |
|||
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27 |
|||
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C19.21,29.16,19.3,28.75,19.3,28.31z" |
|||
/> |
|||
</g> |
|||
</g> |
|||
</svg> |
|||
@ -0,0 +1,17 @@ |
|||
<script> |
|||
import { Icon } from "@budibase/bbui" |
|||
</script> |
|||
|
|||
<a target="_blank" href="https://github.com/Budibase/budibase/discussions"> |
|||
<Icon hoverable name="Help" size="XXL" /> |
|||
</a> |
|||
|
|||
<style> |
|||
a { |
|||
color: inherit; |
|||
position: absolute; |
|||
bottom: var(--spacing-m); |
|||
right: var(--spacing-m); |
|||
border-radius: 55%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,14 @@ |
|||
<script> |
|||
import { Body } from "@budibase/bbui" |
|||
</script> |
|||
|
|||
<div class="root"> |
|||
<Body size="S">This action doesn't require any additional settings.</Body> |
|||
</div> |
|||
|
|||
<style> |
|||
.root { |
|||
max-width: 800px; |
|||
margin: 0 auto; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,114 @@ |
|||
<script> |
|||
import { |
|||
Button, |
|||
Icon, |
|||
DrawerContent, |
|||
Layout, |
|||
Input, |
|||
Combobox, |
|||
} from "@budibase/bbui" |
|||
import { flip } from "svelte/animate" |
|||
import { dndzone } from "svelte-dnd-action" |
|||
import { generate } from "shortid" |
|||
import { store } from "builderStore" |
|||
|
|||
export let links = [] |
|||
|
|||
const flipDurationMs = 150 |
|||
|
|||
$: links.forEach(link => { |
|||
if (!link.id) { |
|||
link.id = generate() |
|||
} |
|||
}) |
|||
|
|||
$: urlOptions = $store.screens |
|||
.map(screen => screen.routing?.route) |
|||
.filter(x => x != null) |
|||
|
|||
const addLink = () => { |
|||
links = [...links, {}] |
|||
} |
|||
|
|||
const removeLink = id => { |
|||
links = links.filter(link => link.id !== id) |
|||
} |
|||
|
|||
const updateLinks = e => { |
|||
links = e.detail.items |
|||
} |
|||
</script> |
|||
|
|||
<DrawerContent> |
|||
<div class="container"> |
|||
<Layout> |
|||
{#if links?.length} |
|||
<div |
|||
class="links" |
|||
use:dndzone={{ |
|||
items: links, |
|||
flipDurationMs, |
|||
dropTargetStyle: { outline: "none" }, |
|||
}} |
|||
on:finalize={updateLinks} |
|||
on:consider={updateLinks} |
|||
> |
|||
{#each links as link (link.id)} |
|||
<div class="link" animate:flip={{ duration: flipDurationMs }}> |
|||
<Icon name="DragHandle" size="XL" /> |
|||
<Input bind:value={link.text} placeholder="Text" /> |
|||
<Combobox |
|||
bind:value={link.url} |
|||
placeholder="URL" |
|||
options={urlOptions} |
|||
/> |
|||
<Icon |
|||
name="Close" |
|||
hoverable |
|||
size="S" |
|||
on:click={() => removeLink(link.id)} |
|||
/> |
|||
</div> |
|||
{/each} |
|||
</div> |
|||
{/if} |
|||
<div class="button-container"> |
|||
<Button secondary icon="Add" on:click={addLink}>Add Link</Button> |
|||
</div> |
|||
</Layout> |
|||
</div> |
|||
</DrawerContent> |
|||
|
|||
<style> |
|||
.container { |
|||
width: 100%; |
|||
max-width: 600px; |
|||
margin: var(--spacing-m) auto; |
|||
} |
|||
.links { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: flex-start; |
|||
align-items: stretch; |
|||
} |
|||
.link { |
|||
padding: 4px 8px; |
|||
gap: var(--spacing-l); |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
border-radius: var(--border-radius-s); |
|||
transition: background-color ease-in-out 130ms; |
|||
} |
|||
.link:hover { |
|||
background-color: var(--spectrum-global-color-gray-100); |
|||
} |
|||
.link > :global(.spectrum-Form-item) { |
|||
flex: 1 1 auto; |
|||
width: 0; |
|||
} |
|||
.button-container { |
|||
margin-left: var(--spacing-l); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,23 @@ |
|||
<script> |
|||
import { Button, ActionButton, Drawer } from "@budibase/bbui" |
|||
import { createEventDispatcher } from "svelte" |
|||
import NavigationDrawer from "./NavigationDrawer.svelte" |
|||
|
|||
export let value = [] |
|||
let drawer |
|||
|
|||
const dispatch = createEventDispatcher() |
|||
const save = () => { |
|||
dispatch("change", value) |
|||
drawer.hide() |
|||
} |
|||
</script> |
|||
|
|||
<ActionButton on:click={drawer.show}>Configure Links</ActionButton> |
|||
<Drawer bind:this={drawer} title={"Navigation Links"}> |
|||
<svelte:fragment slot="description"> |
|||
Configure the links in your navigation bar. |
|||
</svelte:fragment> |
|||
<Button cta slot="buttons" on:click={save}>Save</Button> |
|||
<NavigationDrawer slot="body" bind:links={value} /> |
|||
</Drawer> |
|||
@ -0,0 +1,75 @@ |
|||
<script> |
|||
import { createEventDispatcher } from "svelte" |
|||
import { ActionButton, Body, Icon, Modal, ModalContent } from "@budibase/bbui" |
|||
|
|||
const dispatch = createEventDispatcher() |
|||
|
|||
export let value = "" |
|||
let selected = value |
|||
|
|||
let modal |
|||
let layoutMap = { |
|||
mainSidebar: { |
|||
name: "Main with Sidebar", |
|||
icon: "ColumnTwoB", |
|||
}, |
|||
sidebarMain: { |
|||
name: "Sidebar with Main", |
|||
icon: "ColumnTwoC", |
|||
}, |
|||
twoColumns: { |
|||
name: "Two columns", |
|||
icon: "ColumnTwoA", |
|||
}, |
|||
threeColumns: { |
|||
name: "Three columns", |
|||
icon: "ViewColumn", |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<ActionButton on:click={modal.show}>{layoutMap[value].name}</ActionButton> |
|||
<Modal bind:this={modal}> |
|||
<ModalContent |
|||
onConfirm={() => dispatch("change", selected)} |
|||
size="L" |
|||
title="Select layout" |
|||
> |
|||
<div class="container"> |
|||
{#each Object.entries(layoutMap) as [key, value]} |
|||
<button |
|||
class:selected={selected === key} |
|||
on:click={() => (selected = key)} |
|||
class="layout" |
|||
> |
|||
<Icon color="white" size="L" name={value.icon} /> |
|||
<Body size="XS">{value.name}</Body> |
|||
</button> |
|||
{/each} |
|||
</div> |
|||
</ModalContent> |
|||
</Modal> |
|||
|
|||
<style> |
|||
.container { |
|||
display: grid; |
|||
grid-gap: 20px; |
|||
grid-template-columns: 1fr 1fr 1fr; |
|||
} |
|||
|
|||
.layout { |
|||
color: var(--spectrum-body-m-text-color, var(--spectrum-alias-text-color)); |
|||
border: none; |
|||
box-sizing: border-box; |
|||
display: grid; |
|||
place-items: center; |
|||
background: var(--background-alt); |
|||
grid-gap: var(--spectrum-alias-grid-margin-xsmall); |
|||
padding: var(--spectrum-alias-item-padding-s); |
|||
transition: 0.3s all; |
|||
border-radius: var(--spacing-s); |
|||
} |
|||
.selected { |
|||
background: var(--spectrum-alias-background-color-tertiary); |
|||
} |
|||
</style> |
|||
@ -1,54 +0,0 @@ |
|||
<script> |
|||
import { Button } from "@budibase/bbui" |
|||
export let remove = false |
|||
</script> |
|||
|
|||
<div class="container"> |
|||
<div class="content"> |
|||
<div class="img"><img src="https://picsum.photos/60/60" alt="zoom" /></div> |
|||
<div class="body"> |
|||
<div class="title">Zoom</div> |
|||
<div class="description"> |
|||
Lorem, ipsum dolor sit amet consectetur adipisicing elit |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="footer"> |
|||
<Button wide error={remove} secondary={!remove} on:click> |
|||
<span>{remove ? "Remove" : "Add"}</span> |
|||
</Button> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
.container { |
|||
display: grid; |
|||
padding: 12px; |
|||
background: var(--light-grey); |
|||
grid-gap: 20px; |
|||
} |
|||
span { |
|||
font-size: 12px; |
|||
font-weight: bold; |
|||
} |
|||
.content { |
|||
display: grid; |
|||
grid-gap: 12px; |
|||
grid-template-columns: 60px auto; |
|||
} |
|||
.title { |
|||
font-size: 14px; |
|||
font-weight: bold; |
|||
} |
|||
.description { |
|||
font-size: 12px; |
|||
} |
|||
.img { |
|||
border-radius: 3px; |
|||
overflow: hidden; |
|||
} |
|||
img { |
|||
height: 60px; |
|||
width: 60px; |
|||
} |
|||
</style> |
|||
@ -1,33 +0,0 @@ |
|||
<script> |
|||
import SettingsModal from "./SettingsModal.svelte" |
|||
import { Modal, Icon } from "@budibase/bbui" |
|||
|
|||
let modal |
|||
</script> |
|||
|
|||
<div |
|||
class="topnavitemright settings" |
|||
data-cy="settings-icon" |
|||
on:click={modal.show} |
|||
> |
|||
<Icon hoverable name="Settings" /> |
|||
</div> |
|||
<Modal bind:this={modal} width="600px"> |
|||
<SettingsModal /> |
|||
</Modal> |
|||
|
|||
<style> |
|||
.topnavitemright { |
|||
cursor: pointer; |
|||
color: var(--grey-7); |
|||
margin: 0 12px 0 0; |
|||
font-weight: 600; |
|||
font-size: 1rem; |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 24px; |
|||
width: 24px; |
|||
} |
|||
</style> |
|||
@ -1,34 +0,0 @@ |
|||
<script> |
|||
import { General, DangerZone } from "./tabs" |
|||
import { ModalContent, Tab, Tabs } from "@budibase/bbui" |
|||
</script> |
|||
|
|||
<ModalContent |
|||
title="Settings" |
|||
showConfirmButton={false} |
|||
showCancelButton={false} |
|||
> |
|||
<div class="container"> |
|||
<Tabs selected="General"> |
|||
<Tab title="General"> |
|||
<General /> |
|||
</Tab> |
|||
<!-- <Tab title="API Keys"> |
|||
<APIKeys /> |
|||
</Tab> --> |
|||
<Tab title="Danger Zone"> |
|||
<DangerZone /> |
|||
</Tab> |
|||
</Tabs> |
|||
</div> |
|||
</ModalContent> |
|||
|
|||
<style> |
|||
.container :global(section > header) { |
|||
/* Fix margin defined in BBUI as L rather than XL */ |
|||
margin-bottom: var(--spacing-xl); |
|||
} |
|||
.container :global(textarea) { |
|||
min-height: 60px; |
|||
} |
|||
</style> |
|||
@ -1,62 +0,0 @@ |
|||
<script> |
|||
import { Input, Label, Link } from "@budibase/bbui" |
|||
import api from "builderStore/api" |
|||
import { notifications } from "@budibase/bbui" |
|||
import { database } from "stores/backend" |
|||
import analytics from "analytics" |
|||
|
|||
let keys = { budibase: "" } |
|||
|
|||
async function updateKey([key, value]) { |
|||
if (key === "budibase") { |
|||
const isValid = await analytics.identifyByApiKey(value) |
|||
if (!isValid) { |
|||
notifications.error("Your API Key is invalid.") |
|||
keys = { ...keys } |
|||
return |
|||
} |
|||
} |
|||
const response = await api.put(`/api/keys/${key}`, { value }) |
|||
const res = await response.json() |
|||
keys = { ...keys, ...res } |
|||
notifications.success("API Key saved.") |
|||
} |
|||
|
|||
// Get Keys |
|||
async function fetchKeys() { |
|||
const response = await api.get(`/api/keys/`) |
|||
const res = await response.json() |
|||
// dont want this to ever be editable, as its fetched based on Api Key |
|||
if (res.userId) delete res.userId |
|||
keys = res |
|||
} |
|||
|
|||
fetchKeys() |
|||
</script> |
|||
|
|||
<div class="container"> |
|||
<Input |
|||
on:change={e => updateKey(["budibase", e.detail])} |
|||
value={keys.budibase} |
|||
label="Budibase Cloud API Key" |
|||
/> |
|||
<Link primary href="https://portal.budi.live"> |
|||
Log in to the Budibase Hosting Portal to get your API Key. → |
|||
</Link> |
|||
<div> |
|||
<Label extraSmall grey>Instance ID (Webhooks)</Label> |
|||
<span>{$database._id}</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
.container { |
|||
display: grid; |
|||
grid-gap: var(--spacing-xl); |
|||
} |
|||
|
|||
span { |
|||
font-size: var(--font-size-xs); |
|||
font-weight: 600; |
|||
} |
|||
</style> |
|||
@ -1,56 +0,0 @@ |
|||
<script> |
|||
import { params, goto } from "@roxi/routify" |
|||
import { Input, Button, Body } from "@budibase/bbui" |
|||
import { del } from "builderStore/api" |
|||
|
|||
let value = "" |
|||
let loading = false |
|||
|
|||
async function deleteApp() { |
|||
loading = true |
|||
const id = $params.application |
|||
await del(`/api/applications/${id}`) |
|||
loading = false |
|||
$goto("/builder") |
|||
} |
|||
</script> |
|||
|
|||
<div class="background"> |
|||
<Body> |
|||
Type |
|||
<b>DELETE</b> |
|||
into the textbox, then click the following button to delete your entire web app. |
|||
</Body> |
|||
<Input |
|||
on:change={e => (value = e.detail)} |
|||
disabled={loading} |
|||
placeholder="" |
|||
/> |
|||
<div class="buttons"> |
|||
<Button |
|||
warning |
|||
disabled={value !== "DELETE" || loading} |
|||
on:click={deleteApp} |
|||
> |
|||
Delete Entire App |
|||
</Button> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
.background { |
|||
display: grid; |
|||
grid-gap: var(--spacing-xl); |
|||
} |
|||
.background :global(p) { |
|||
line-height: 1.2; |
|||
margin: 0; |
|||
} |
|||
|
|||
.buttons { |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: flex-end; |
|||
align-items: center; |
|||
} |
|||
</style> |
|||
@ -1,97 +0,0 @@ |
|||
<script> |
|||
import { Input, TextArea } from "@budibase/bbui" |
|||
import { store, hostingStore } from "builderStore" |
|||
import api from "builderStore/api" |
|||
import { object, string } from "yup" |
|||
import { onMount } from "svelte" |
|||
import { get } from "svelte/store" |
|||
|
|||
let nameValidation, nameError |
|||
let urlValidation, urlError |
|||
|
|||
$: checkName($store.name) |
|||
$: checkUrl($store.url) |
|||
|
|||
async function updateApplication(data) { |
|||
const response = await api.put(`/api/applications/${$store.appId}`, data) |
|||
await response.json() |
|||
store.update(state => { |
|||
state = { |
|||
...state, |
|||
...data, |
|||
} |
|||
return state |
|||
}) |
|||
} |
|||
|
|||
async function checkValidation(input, validation) { |
|||
if (!input || !validation) { |
|||
return |
|||
} |
|||
try { |
|||
await object(validation).validate(input, { abortEarly: false }) |
|||
} catch (error) { |
|||
if (!error || !error.inner) return "" |
|||
return error.inner.reduce((acc, err) => { |
|||
return acc + err.message |
|||
}, "") |
|||
} |
|||
} |
|||
|
|||
async function checkName(name) { |
|||
nameError = await checkValidation({ name }, nameValidation) |
|||
} |
|||
|
|||
async function checkUrl(url) { |
|||
urlError = await checkValidation({ url: url.toLowerCase() }, urlValidation) |
|||
} |
|||
|
|||
onMount(async () => { |
|||
const nameError = "Your application must have a name.", |
|||
urlError = "Your application must have a URL." |
|||
await hostingStore.actions.fetchDeployedApps() |
|||
const existingAppNames = get(hostingStore).deployedAppNames |
|||
const existingAppUrls = get(hostingStore).deployedAppUrls |
|||
const nameIdx = existingAppNames.indexOf(get(store).name) |
|||
const urlIdx = existingAppUrls.indexOf(get(store).url) |
|||
if (nameIdx !== -1) { |
|||
existingAppNames.splice(nameIdx, 1) |
|||
} |
|||
if (urlIdx !== -1) { |
|||
existingAppUrls.splice(urlIdx, 1) |
|||
} |
|||
nameValidation = { |
|||
name: string().required(nameError).notOneOf(existingAppNames), |
|||
} |
|||
urlValidation = { |
|||
url: string().required(urlError).notOneOf(existingAppUrls), |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<div class="container"> |
|||
<Input |
|||
on:change={e => updateApplication({ name: e.detail })} |
|||
value={$store.name} |
|||
error={nameError} |
|||
label="App Name" |
|||
/> |
|||
<Input |
|||
on:change={e => updateApplication({ url: e.detail })} |
|||
value={$store.url} |
|||
error={urlError} |
|||
label="App URL" |
|||
/> |
|||
<TextArea |
|||
on:change={e => updateApplication({ description: e.detail })} |
|||
value={$store.description} |
|||
label="App Description" |
|||
/> |
|||
</div> |
|||
|
|||
<style> |
|||
.container { |
|||
display: grid; |
|||
grid-gap: var(--spacing-xl); |
|||
} |
|||
</style> |
|||
@ -1,40 +0,0 @@ |
|||
<script> |
|||
import Integration from "../Integration.svelte" |
|||
</script> |
|||
|
|||
<div class="container"> |
|||
<div class="title">Your Integrations</div> |
|||
<div class="integrations"> |
|||
<Integration remove /> |
|||
<Integration remove /> |
|||
<Integration remove /> |
|||
<Integration remove /> |
|||
</div> |
|||
<div class="apps">Recommended apps</div> |
|||
<div class="integrations"> |
|||
<Integration /> |
|||
<Integration /> |
|||
<Integration /> |
|||
<Integration /> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
.container { |
|||
display: grid; |
|||
grid-gap: 16px; |
|||
} |
|||
.integrations { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
grid-gap: 20px; |
|||
} |
|||
.title { |
|||
font-size: 18px; |
|||
font-weight: bold; |
|||
} |
|||
.apps { |
|||
font-size: 14px; |
|||
font-weight: bold; |
|||
} |
|||
</style> |
|||
@ -1 +0,0 @@ |
|||
Permissions |
|||
@ -1,5 +0,0 @@ |
|||
export { default as General } from "./General.svelte" |
|||
export { default as Integrations } from "./Integrations.svelte" |
|||
export { default as Permissions } from "./Permissions.svelte" |
|||
export { default as APIKeys } from "./APIKeys.svelte" |
|||
export { default as DangerZone } from "./DangerZone.svelte" |
|||
@ -1,13 +1 @@ |
|||
<script> |
|||
import { params } from "@roxi/routify" |
|||
import { queries } from "stores/backend" |
|||
|
|||
if ($params.query) { |
|||
const query = $queries.list.find(m => m._id === $params.query) |
|||
if (query) { |
|||
queries.select(query) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<slot /> |
|||
|
|||
@ -0,0 +1,81 @@ |
|||
<script> |
|||
import { Button, Heading, Body, Layout, Modal, Divider } from "@budibase/bbui" |
|||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte" |
|||
import ICONS from "components/backend/DatasourceNavigator/icons" |
|||
import { tables } from "stores/backend" |
|||
import { goto } from "@roxi/routify" |
|||
|
|||
let modal |
|||
</script> |
|||
|
|||
<Modal bind:this={modal}> |
|||
<CreateTableModal /> |
|||
</Modal> |
|||
|
|||
<section> |
|||
<Layout> |
|||
<header> |
|||
<svelte:component this={ICONS.BUDIBASE} height="26" width="26" /> |
|||
<Heading size="M">Budibase Internal</Heading> |
|||
</header> |
|||
<Body size="S" grey lh |
|||
>Budibase internal tables are part of your app, the data will be stored in |
|||
your apps context.</Body |
|||
> |
|||
<Divider /> |
|||
<Heading size="S">Tables</Heading> |
|||
<div class="table-list"> |
|||
{#each $tables.list.filter(table => table.type !== "external") as table} |
|||
<div |
|||
class="table-list-item" |
|||
on:click={$goto(`../../table/${table._id}`)} |
|||
> |
|||
<Body size="S">{table.name}</Body> |
|||
{#if table.primaryDisplay} |
|||
<Body size="S">display column: {table.primaryDisplay}</Body> |
|||
{/if} |
|||
</div> |
|||
{/each} |
|||
</div> |
|||
<div> |
|||
<Button cta on:click={modal.show}>Create new table</Button> |
|||
</div> |
|||
</Layout> |
|||
</section> |
|||
|
|||
<style> |
|||
section { |
|||
margin: 0 auto; |
|||
width: 640px; |
|||
} |
|||
|
|||
header { |
|||
margin: 0 0 var(--spacing-xs) 0; |
|||
display: flex; |
|||
gap: var(--spacing-l); |
|||
align-items: center; |
|||
} |
|||
|
|||
.table-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: var(--spacing-m); |
|||
} |
|||
|
|||
.table-list-item { |
|||
border-radius: var(--border-radius-m); |
|||
background: var(--background); |
|||
border: var(--border-dark); |
|||
display: grid; |
|||
grid-template-columns: 2fr 0.75fr 20px; |
|||
align-items: center; |
|||
padding: var(--spacing-m); |
|||
gap: var(--layout-xs); |
|||
transition: 200ms background ease; |
|||
} |
|||
|
|||
.table-list-item:hover { |
|||
background: var(--grey-1); |
|||
cursor: pointer; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,13 @@ |
|||
<script> |
|||
import { params } from "@roxi/routify" |
|||
import { tables } from "stores/backend" |
|||
|
|||
if ($params.selectedTable) { |
|||
const table = $tables.list.find(m => m._id === $params.selectedTable) |
|||
if (table) { |
|||
tables.select(table) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<slot /> |
|||
@ -0,0 +1,16 @@ |
|||
<script> |
|||
import TableDataTable from "components/backend/DataTable/DataTable.svelte" |
|||
import { tables, database } from "stores/backend" |
|||
</script> |
|||
|
|||
{#if $database?._id && $tables?.selected?.name} |
|||
<TableDataTable /> |
|||
{:else}<i>Create your first table to start building</i>{/if} |
|||
|
|||
<style> |
|||
i { |
|||
font-size: var(--font-size-m); |
|||
color: var(--grey-5); |
|||
margin-top: 2px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,10 @@ |
|||
<script> |
|||
import { params } from "@roxi/routify" |
|||
import RelationshipDataTable from "components/backend/DataTable/RelationshipDataTable.svelte" |
|||
</script> |
|||
|
|||
<RelationshipDataTable |
|||
tableId={$params.selectedTable} |
|||
rowId={$params.selectedRow} |
|||
fieldName={decodeURI($params.selectedField)} |
|||
/> |
|||
@ -0,0 +1,6 @@ |
|||
<script> |
|||
import { goto } from "@roxi/routify" |
|||
$goto("../../") |
|||
</script> |
|||
|
|||
<!-- routify:options index=false --> |
|||
@ -0,0 +1,6 @@ |
|||
<script> |
|||
import { goto } from "@roxi/routify" |
|||
$goto("../") |
|||
</script> |
|||
|
|||
<!-- routify:options index=false --> |
|||
@ -0,0 +1,19 @@ |
|||
<script> |
|||
import { tables } from "stores/backend" |
|||
import { goto, leftover } from "@roxi/routify" |
|||
import { onMount } from "svelte" |
|||
|
|||
onMount(async () => { |
|||
// navigate to first table in list, if not already selected |
|||
// and this is the final url (i.e. no selectedTable) |
|||
if ( |
|||
!$leftover && |
|||
$tables.list.length > 0 |
|||
// (!$tables.selected || !$tables.selected._id) |
|||
) { |
|||
$goto(`./${$tables.list[0]._id}`) |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<slot /> |
|||
@ -0,0 +1,21 @@ |
|||
<script> |
|||
import { goto } from "@roxi/routify" |
|||
import { onMount } from "svelte" |
|||
import { tables } from "stores/backend" |
|||
|
|||
onMount(async () => { |
|||
$tables.list.length > 0 && $goto(`./${$tables.list[0]._id}`) |
|||
}) |
|||
</script> |
|||
|
|||
{#if $tables.list.length === 0} |
|||
<i>Create your first table to start building</i> |
|||
{:else}<i>Select a table to edit</i>{/if} |
|||
|
|||
<style> |
|||
i { |
|||
font-size: var(--font-size-m); |
|||
color: var(--grey-5); |
|||
margin-top: 2px; |
|||
} |
|||
</style> |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue