Merge branch 'master' of https://github.com/Budibase/budibase into property-panel/screen-and-page-props
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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 400 400" style="enable-background:new 0 0 400 400;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#6A78D1;}
|
||||
.st2{fill:#49C39E;}
|
||||
.st3{fill:#F2545B;}
|
||||
.st4{fill:#F5C26B;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M215,14.1l136.2,79.8c9.3,5.4,15,15.5,15,26.4v159.5c0,10.9-5.7,20.9-15,26.4L215,385.9
|
||||
c-9.3,5.4-20.7,5.4-30,0L48.8,306.2c-9.3-5.4-15-15.5-15-26.4V120.2c0-10.9,5.7-20.9,15-26.4L185,14.1
|
||||
C194.3,8.6,205.7,8.6,215,14.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M288.8,273.7l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6
|
||||
c3.6-1.9,8-1.9,11.6,0l83,43.6C297.1,258.3,297.1,269.4,288.8,273.7z"/>
|
||||
<path class="st2" d="M288.8,231.2l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6
|
||||
c3.6-1.9,8-1.9,11.6,0l83,43.6C297.1,215.7,297.1,226.9,288.8,231.2z"/>
|
||||
<path class="st3" d="M288.8,188.6l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6
|
||||
c3.6-1.9,8-1.9,11.6,0l83,43.6C297.1,173.1,297.1,184.3,288.8,188.6z"/>
|
||||
<path class="st4" d="M288.8,146l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6c3.6-1.9,8-1.9,11.6,0
|
||||
l83,43.6C297.1,130.6,297.1,141.7,288.8,146z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
|
@ -1,8 +1,7 @@
|
|||
/* Budibase Component Styles */
|
||||
.header {
|
||||
font-size: 0.75rem;
|
||||
color: #000333;
|
||||
opacity: 0.4;
|
||||
color: var(--ink);
|
||||
text-transform: uppercase;
|
||||
margin-top: 1rem;
|
||||
font-weight: 500;
|
||||
|
@ -81,10 +80,9 @@
|
|||
max-width: 250px;
|
||||
height: 35px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #DBDBDB;
|
||||
border: 1px solid var(--grey-dark);
|
||||
text-align: left;
|
||||
letter-spacing: 0.7px;
|
||||
color: #000333;
|
||||
color: var(--ink);
|
||||
font-size: 16px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
@ -103,27 +101,32 @@
|
|||
}
|
||||
|
||||
.budibase__table {
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid var(--grey-dark);
|
||||
background: #fff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.budibase__table thead {
|
||||
background: #fafafa;
|
||||
background: var(--blue-light);
|
||||
}
|
||||
|
||||
.budibase__table thead > tr > th {
|
||||
color: var(--button-text);
|
||||
color: var(--ink);
|
||||
text-transform: capitalize;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.budibase__table tr {
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-bottom: 1px solid var(--grey-light);
|
||||
}
|
||||
|
||||
.button--toggled {
|
||||
background: #fafafa;
|
||||
color: var(--button-text);
|
||||
padding: 10px;
|
||||
background: var(--blue-light);
|
||||
color: var(--ink-light);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
}
|
|
@ -3,6 +3,7 @@ const apiCall = method => async (url, body) => {
|
|||
method: method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Budibase Builder",
|
||||
},
|
||||
body: body && JSON.stringify(body),
|
||||
})
|
||||
|
@ -14,11 +15,11 @@ const apiCall = method => async (url, body) => {
|
|||
return response
|
||||
}
|
||||
|
||||
const post = apiCall("POST")
|
||||
const get = apiCall("GET")
|
||||
const patch = apiCall("PATCH")
|
||||
const del = apiCall("DELETE")
|
||||
const put = apiCall("PUT")
|
||||
export const post = apiCall("POST")
|
||||
export const get = apiCall("GET")
|
||||
export const patch = apiCall("PATCH")
|
||||
export const del = apiCall("DELETE")
|
||||
export const put = apiCall("PUT")
|
||||
|
||||
export default {
|
||||
post,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
export let disabled = false
|
||||
export let hidden = false
|
||||
export let secondary = false
|
||||
export let primary = true
|
||||
export let cancel = false
|
||||
export let alert = false
|
||||
|
@ -11,6 +12,7 @@
|
|||
on:click
|
||||
class="button"
|
||||
class:hidden
|
||||
class:secondary
|
||||
class:primary
|
||||
class:alert
|
||||
class:cancel
|
||||
|
@ -22,12 +24,14 @@
|
|||
<style>
|
||||
.primary {
|
||||
color: #ffffff;
|
||||
background: #0055ff;
|
||||
background: var(--blue);
|
||||
border: solid 1px var(--blue);
|
||||
}
|
||||
|
||||
.alert {
|
||||
color: rgba(255, 0, 31, 1);
|
||||
background: rgba(255, 0, 31, 0.1);
|
||||
color: white;
|
||||
background: #e26d69;
|
||||
border: solid 1px #e26d69;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
|
@ -35,18 +39,22 @@
|
|||
background: none;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
color: var(--ink);
|
||||
border: solid 1px var(--grey-dark);
|
||||
background: white;
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
font-weight: 500;
|
||||
border-radius: 3px;
|
||||
padding: 10px 20px;
|
||||
height: 45px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
filter: saturate(90%);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
background: var(--secondary80);
|
||||
color: var(--white);
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
width: 95%;
|
||||
height: 100px;
|
||||
height: 200px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import {onMount} from "svelte"
|
||||
import { onMount } from "svelte"
|
||||
import { buildStyle } from "../../helpers.js"
|
||||
export let value = ""
|
||||
export let textAlign = "left"
|
||||
|
@ -7,22 +7,30 @@
|
|||
export let placeholder = ""
|
||||
export let suffix = ""
|
||||
export let onChange = val => {}
|
||||
|
||||
|
||||
let centerPlaceholder = textAlign === "center"
|
||||
|
||||
let style = buildStyle({ width, textAlign })
|
||||
|
||||
|
||||
function handleChange(val) {
|
||||
value = val
|
||||
let _value = value !== "auto" ? value + suffix : value
|
||||
onChange(_value)
|
||||
}
|
||||
|
||||
$: displayValue = suffix && value && value.endsWith(suffix) ? value.replace(new RegExp(`${suffix}$`), "") : (value || "")
|
||||
|
||||
$: displayValue =
|
||||
suffix && value && value.endsWith(suffix)
|
||||
? value.replace(new RegExp(`${suffix}$`), "")
|
||||
: value || ""
|
||||
</script>
|
||||
|
||||
<input class:centerPlaceholder type="text" value={displayValue} {placeholder} {style} on:change={e => handleChange(e.target.value)} />
|
||||
<input
|
||||
class:centerPlaceholder
|
||||
type="text"
|
||||
value={displayValue}
|
||||
{placeholder}
|
||||
{style}
|
||||
on:change={e => handleChange(e.target.value)} />
|
||||
|
||||
<style>
|
||||
input {
|
||||
|
@ -43,7 +51,7 @@
|
|||
outline: none;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
input::placeholder {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,11 @@
|
|||
|
||||
function handleChange(val, idx) {
|
||||
value.splice(idx, 1, val !== "auto" ? val + suffix : val)
|
||||
|
||||
|
||||
value = value
|
||||
let _value = value.map(v => (!v.endsWith(suffix) && v !== "auto" ? v + suffix : v))
|
||||
let _value = value.map(v =>
|
||||
!v.endsWith(suffix) && v !== "auto" ? v + suffix : v
|
||||
)
|
||||
onChange(_value)
|
||||
}
|
||||
|
||||
|
@ -44,5 +46,4 @@
|
|||
.inputs-group {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -50,10 +50,10 @@
|
|||
<style>
|
||||
.uk-modal-dialog {
|
||||
border-radius: 0.3rem;
|
||||
width: 60%;
|
||||
width: 520px;
|
||||
height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -20,11 +20,9 @@
|
|||
<style>
|
||||
.select-container {
|
||||
font-size: 14px;
|
||||
color: var(--secondary60);
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
max-width: 400px;
|
||||
min-width: 275px;
|
||||
border: var(--grey-dark) 1px solid;
|
||||
max-width: 256px;
|
||||
}
|
||||
|
||||
.adjusted {
|
||||
|
@ -43,7 +41,7 @@
|
|||
font-family: sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #000333;
|
||||
color: var(--ink);
|
||||
padding: 0 40px 0px 20px;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
|
@ -63,6 +61,6 @@
|
|||
width: 30px;
|
||||
height: 30px;
|
||||
pointer-events: none;
|
||||
color: var(--secondary100);
|
||||
color: var(--ink);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -145,19 +145,19 @@
|
|||
}
|
||||
|
||||
table {
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid var(--grey-dark);
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
thead {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ccc;
|
||||
background: var(--blue-light);
|
||||
border: 1px solid var(--grey-dark);
|
||||
}
|
||||
|
||||
thead th {
|
||||
color: var(--button-text);
|
||||
color: var(--ink);
|
||||
text-transform: capitalize;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
|
@ -166,14 +166,14 @@
|
|||
}
|
||||
|
||||
tbody tr {
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-bottom: 1px solid var(--grey-dark);
|
||||
transition: 0.3s background-color;
|
||||
color: var(--secondary100);
|
||||
color: var(--ink);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background: #fafafa;
|
||||
background: var(--grey-light);
|
||||
}
|
||||
|
||||
.table-controls {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<div class="heading">
|
||||
{#if !showFieldView}
|
||||
<i class="ri-list-settings-line button--toggled" />
|
||||
<h3 class="budibase__title--3">Create / Edit Model</h3>
|
||||
|
@ -43,22 +43,20 @@
|
|||
<i class="ri-file-list-line button--toggled" />
|
||||
<h3 class="budibase__title--3">Create / Edit Field</h3>
|
||||
{/if}
|
||||
</header>
|
||||
</div>
|
||||
{#if !showFieldView}
|
||||
<div class="padding">
|
||||
<h4 class="budibase__label--big">Settings</h4>
|
||||
|
||||
{#if $store.errors && $store.errors.length > 0}
|
||||
<ErrorsBox errors={$store.errors} />
|
||||
{/if}
|
||||
|
||||
<Textbox label="Name" bind:text={model.name} />
|
||||
|
||||
<div class="textbox">
|
||||
<Textbox label="Name" bind:text={model.name} />
|
||||
</div>
|
||||
<div class="table-controls">
|
||||
<span class="budibase__label--big">Fields</span>
|
||||
<h4 class="hoverable new-field" on:click={() => (showFieldView = true)}>
|
||||
<span class="label">Fields</span>
|
||||
<div class="hoverable new-field" on:click={() => (showFieldView = true)}>
|
||||
Add new field
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="uk-table fields-table budibase__table">
|
||||
|
@ -67,7 +65,6 @@
|
|||
<th>Edit</th>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Values</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -90,9 +87,9 @@
|
|||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="uk-margin">
|
||||
<footer>
|
||||
<ActionButton color="secondary" on:click={saveModel}>Save</ActionButton>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
{:else}
|
||||
<FieldView
|
||||
|
@ -104,41 +101,63 @@
|
|||
|
||||
<style>
|
||||
.padding {
|
||||
padding: 20px;
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.textbox {
|
||||
margin: 0px 40px 0px 40px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.new-field {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: var(--button-text);
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.fields-table {
|
||||
margin: 1rem 1rem 0rem 0rem;
|
||||
margin: 8px 40px 0px 40px;
|
||||
border-collapse: collapse;
|
||||
width: 88%;
|
||||
}
|
||||
|
||||
tbody > tr:hover {
|
||||
background-color: var(--primary10);
|
||||
background-color: var(--grey-light);
|
||||
}
|
||||
|
||||
.table-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0px 40px;
|
||||
}
|
||||
|
||||
.ri-more-line:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
heading {
|
||||
padding: 20px 20px 0 20px;
|
||||
.heading {
|
||||
padding: 40px 40px 0 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 0 10px;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: var(--grey-light);
|
||||
margin-top: 40px;
|
||||
padding: 20px 40px 20px 40px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -79,19 +79,28 @@
|
|||
</form>
|
||||
</div>
|
||||
<footer>
|
||||
<div class="button">
|
||||
<ActionButton secondary on:click={goBack}>Cancel</ActionButton>
|
||||
</div>
|
||||
<ActionButton primary on:click={save}>Save</ActionButton>
|
||||
<ActionButton alert on:click={goBack}>Cancel</ActionButton>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
.root {
|
||||
margin: 20px;
|
||||
margin: 40px;
|
||||
}
|
||||
footer {
|
||||
padding: 20px;
|
||||
padding: 20px 40px;
|
||||
border-radius: 0 0 5px 5px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: #fafafa;
|
||||
background: var(--grey-light);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -39,51 +39,49 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<heading>
|
||||
<div class="header">
|
||||
<i class="ri-eye-line button--toggled" />
|
||||
<h3 class="budibase__title--3">Create / Edit View</h3>
|
||||
</heading>
|
||||
</div>
|
||||
<form on:submit|preventDefault class="uk-form-stacked root">
|
||||
<h4 class="budibase__label--big">Settings</h4>
|
||||
{#if $store.errors && $store.errors.length > 0}
|
||||
<ErrorsBox errors={$store.errors} />
|
||||
{/if}
|
||||
<div class="uk-grid-small" uk-grid>
|
||||
<div class="uk-width-1-2@s">
|
||||
<Textbox bind:text={view.name} label="Name" />
|
||||
<div class="main">
|
||||
<div class="uk-grid-small" uk-grid>
|
||||
<div class="uk-width-1-2@s">
|
||||
<Textbox bind:text={view.name} label="Name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="code-snippets">
|
||||
{#each Object.values(SNIPPET_EDITORS) as snippetType}
|
||||
<span
|
||||
class="snippet-selector__heading hoverable"
|
||||
class:highlighted={currentSnippetEditor === snippetType}
|
||||
on:click={() => (currentSnippetEditor = snippetType)}>
|
||||
{snippetType}
|
||||
</span>
|
||||
{/each}
|
||||
{#if currentSnippetEditor === SNIPPET_EDITORS.MAP}
|
||||
<CodeArea bind:text={view.map} label="Map" />
|
||||
{:else if currentSnippetEditor === SNIPPET_EDITORS.FILTER}
|
||||
<CodeArea bind:text={view.filter} label="Filter" />
|
||||
{:else if currentSnippetEditor === SNIPPET_EDITORS.REDUCE}
|
||||
<CodeArea bind:text={view.reduce} label="Reduce" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="budibase__label--big">Snippets</h4>
|
||||
{#each Object.values(SNIPPET_EDITORS) as snippetType}
|
||||
<span
|
||||
class="snippet-selector__heading hoverable"
|
||||
class:highlighted={currentSnippetEditor === snippetType}
|
||||
on:click={() => (currentSnippetEditor = snippetType)}>
|
||||
{snippetType}
|
||||
</span>
|
||||
{/each}
|
||||
{#if currentSnippetEditor === SNIPPET_EDITORS.MAP}
|
||||
<CodeArea bind:text={view.map} label="Map" />
|
||||
{:else if currentSnippetEditor === SNIPPET_EDITORS.FILTER}
|
||||
<CodeArea bind:text={view.filter} label="Filter" />
|
||||
{:else if currentSnippetEditor === SNIPPET_EDITORS.REDUCE}
|
||||
<CodeArea bind:text={view.reduce} label="Reduce" />
|
||||
{/if}
|
||||
|
||||
<ActionButton color="secondary" on:click={saveView}>Save</ActionButton>
|
||||
<ActionButton alert on:click={deleteView}>Delete</ActionButton>
|
||||
<div class="buttons">
|
||||
<div class="button">
|
||||
<ActionButton secondary on:click={deleteView}>Delete</ActionButton>
|
||||
</div>
|
||||
<ActionButton color="secondary" on:click={saveView}>Save</ActionButton>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
.root {
|
||||
height: 100%;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.snippet-selector__heading {
|
||||
margin-right: 20px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
|
@ -92,11 +90,38 @@
|
|||
|
||||
h3 {
|
||||
margin: 0 0 0 10px;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
heading {
|
||||
padding: 20px 20px 0 20px;
|
||||
.snippet-selector__heading {
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
color: var(--ink-lighter);
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 20px 40px 0 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin: 20px 40px 0px 40px;
|
||||
}
|
||||
|
||||
.code-snippets {
|
||||
margin: 20px 0px 20px 0px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
background-color: var(--grey-light);
|
||||
margin: 0 40px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
</script>
|
||||
|
||||
<form on:submit|preventDefault class="uk-form-stacked">
|
||||
<div>
|
||||
<div class="main">
|
||||
<div class="heading">
|
||||
<i class="ri-list-settings-line button--toggled" />
|
||||
<div class="title">Create User</div>
|
||||
</div>
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="form-stacked-text">Username</label>
|
||||
<input class="uk-input" type="text" bind:value={username} />
|
||||
|
@ -41,18 +45,40 @@
|
|||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
||||
<div class="button">
|
||||
<ActionButton secondary on:click={onClosed}>Cancel</ActionButton>
|
||||
</div>
|
||||
<ActionButton disabled={!valid} on:click={createUser}>Save</ActionButton>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
div {
|
||||
padding: 30px;
|
||||
.main {
|
||||
padding: 40px 40px 20px 40px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 20px;
|
||||
background: #fafafa;
|
||||
border-radius: 0.5rem;
|
||||
background: var(--grey-light);
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import { AppsIcon, InfoIcon, CloseIcon } from "components/common/Icons/"
|
||||
import { getContext } from "svelte"
|
||||
import { fade } from "svelte/transition"
|
||||
import { post } from "builderStore/api"
|
||||
|
||||
const { open, close } = getContext("simple-modal")
|
||||
|
||||
|
@ -33,15 +34,7 @@
|
|||
const data = { name, description }
|
||||
loading = true
|
||||
try {
|
||||
const response = await fetch("/api/applications", {
|
||||
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
||||
credentials: "same-origin", // include, *same-origin, omit
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||
})
|
||||
const response = await post("/api/applications", data)
|
||||
|
||||
const res = await response.json()
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ export default ({
|
|||
|
||||
body, html {
|
||||
height: 100%!important;
|
||||
font-family: Roboto !important;
|
||||
}
|
||||
.lay-__screenslot__text {
|
||||
width: 100%;
|
||||
|
|
|
@ -151,7 +151,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="root" on:click|stopPropagation={() => {}}>
|
||||
<div class="root boundary" on:click|stopPropagation={() => {}}>
|
||||
<button>
|
||||
<MoreIcon />
|
||||
</button>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<Input on:change={onChange} value={parameter.value} />
|
||||
<Input {onChange} value={parameter.value} />
|
||||
<button on:click={() => (isOpen = !isOpen)}>
|
||||
<div class="icon" style={`transform: rotate(${isOpen ? 0 : 90}deg);`}>
|
||||
<ArrowDownIcon size={36} />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import {buildStyle} from "../../helpers.js"
|
||||
import { buildStyle } from "../../helpers.js"
|
||||
export let value = ""
|
||||
export let text = ""
|
||||
export let icon = ""
|
||||
|
@ -8,19 +8,24 @@
|
|||
export let selected = false
|
||||
export let fontWeight = ""
|
||||
|
||||
$: style = buildStyle({padding, fontWeight})
|
||||
$: style = buildStyle({ padding, fontWeight })
|
||||
$: useIcon = !!icon
|
||||
</script>
|
||||
|
||||
<div class="flatbutton" {style} class:selected on:click={() => onClick(value || text)}>
|
||||
<div
|
||||
class="flatbutton"
|
||||
{style}
|
||||
class:selected
|
||||
on:click={() => onClick(value || text)}>
|
||||
{#if useIcon}
|
||||
<i class={icon} />
|
||||
{:else}
|
||||
<span>{@html text}</span>
|
||||
<span>
|
||||
{@html text}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.flatbutton {
|
||||
cursor: pointer;
|
||||
|
@ -41,8 +46,8 @@
|
|||
background: var(--ink-light);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
i{
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -28,10 +28,8 @@
|
|||
onChange(val)
|
||||
}
|
||||
|
||||
|
||||
const checkSelected = val =>
|
||||
isMultiSelect ? value.includes(val) : value === val
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flatbutton-group">
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
import { backendUiStore } from "builderStore"
|
||||
|
||||
export let value
|
||||
</script>
|
||||
|
||||
<div class="uk-margin block-field">
|
||||
<div class="uk-form-controls">
|
||||
<select class="budibase__input" on:change {value}>
|
||||
<option value="" />
|
||||
{#each $backendUiStore.models as model}
|
||||
<option value={model._id}>{model.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { onMount, beforeUpdate } from "svelte"
|
||||
import {buildStyle} from "../../helpers.js"
|
||||
import { buildStyle } from "../../helpers.js"
|
||||
export let options = []
|
||||
export let value = ""
|
||||
export let styleBindingProperty
|
||||
|
@ -214,10 +214,10 @@
|
|||
height: auto;
|
||||
padding: 5px 0px;
|
||||
cursor: pointer;
|
||||
padding-left: 10px
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
li:hover {
|
||||
background-color:#e6e6e6
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Input from "../common/Input.svelte"
|
||||
import OptionSelect from "./OptionSelect.svelte"
|
||||
import Checkbox from "../common/Checkbox.svelte"
|
||||
import ModelSelect from "components/userInterface/ModelSelect.svelte"
|
||||
|
||||
import { all } from "./propertyCategories.js"
|
||||
|
||||
|
@ -261,25 +262,47 @@ export default {
|
|||
},
|
||||
{
|
||||
name: "Login",
|
||||
_component: "@budibase/standard-components/login",
|
||||
description:
|
||||
"A component that automatically generates a login screen for your app.",
|
||||
icon: "ri-login-box-fill",
|
||||
children: [],
|
||||
properties: { design: { ...all } },
|
||||
properties: {
|
||||
design: { ...all },
|
||||
settings: [
|
||||
{
|
||||
label: "Name",
|
||||
key: "name",
|
||||
control: Input,
|
||||
},
|
||||
{
|
||||
label: "Logo",
|
||||
key: "logo",
|
||||
control: Input,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Table",
|
||||
_component: "@budibase/standard-components/datatable",
|
||||
description: "A component that generates a table from your data.",
|
||||
icon: "ri-archive-drawer-fill",
|
||||
properties: { design: { ...all } },
|
||||
properties: {
|
||||
design: { ...all },
|
||||
settings: [{ label: "Model", key: "model", control: ModelSelect }],
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "Form",
|
||||
description: "A component that generates a form from your data.",
|
||||
icon: "ri-file-edit-fill",
|
||||
properties: { design: { ...all } },
|
||||
_component: "@budibase/materialdesign-components/Form",
|
||||
properties: {
|
||||
design: { ...all },
|
||||
settings: [{ label: "Model", key: "model", control: ModelSelect }],
|
||||
},
|
||||
_component: "@budibase/standard-components/dataform",
|
||||
template: {
|
||||
component: "@budibase/materialdesign-components/Form",
|
||||
description: "Form for saving a record",
|
||||
|
@ -292,7 +315,10 @@ export default {
|
|||
_component: "@budibase/standard-components/datachart",
|
||||
description: "Shiny chart",
|
||||
icon: "ri-bar-chart-fill",
|
||||
properties: { design: { ...all } },
|
||||
properties: {
|
||||
design: { ...all },
|
||||
settings: [{ label: "Model", key: "model", control: ModelSelect }],
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
|
@ -300,7 +326,10 @@ export default {
|
|||
_component: "@budibase/standard-components/datalist",
|
||||
description: "Shiny list",
|
||||
icon: "ri-file-list-fill",
|
||||
properties: { design: { ...all } },
|
||||
properties: {
|
||||
design: { ...all },
|
||||
settings: [{ label: "Model", key: "model", control: ModelSelect }],
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
|
@ -334,10 +363,15 @@ export default {
|
|||
"A component for handling the navigation within your app.",
|
||||
icon: "ri-navigation-fill",
|
||||
children: [],
|
||||
properties: {
|
||||
design: { ...all },
|
||||
settings: [{ label: "Logo URL", key: "logoUrl", control: Input }, ],
|
||||
},
|
||||
properties: {
|
||||
design: { ...all },
|
||||
settings: [
|
||||
{ label: "Logo URL", key: "logoUrl", control: Input },
|
||||
{ label: "Title", key: "title", control: Input },
|
||||
{ label: "Color", key: "color", control: Input },
|
||||
{ label: "Background", key: "backgroundColor", control: Input },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
</script>
|
||||
|
||||
<div class="uk-margin block-field">
|
||||
<label class="uk-form-label">Model</label>
|
||||
<div class="uk-form-controls">
|
||||
<select class="budibase__input" bind:value>
|
||||
<option value="" />
|
||||
{#each $backendUiStore.models as model}
|
||||
<option value={model}>{model.name}</option>
|
||||
{/each}
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 6.7 KiB |
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import Modal from "svelte-simple-modal"
|
||||
import { store } from "builderStore"
|
||||
import { get } from "builderStore/api"
|
||||
|
||||
import { fade } from "svelte/transition"
|
||||
import { isActive, goto, layout } from "@sveltech/routify"
|
||||
|
@ -14,7 +15,7 @@
|
|||
let promise = getPackage()
|
||||
|
||||
async function getPackage() {
|
||||
const res = await fetch(`/api/${application}/appPackage`)
|
||||
const res = await get(`/api/${application}/appPackage`)
|
||||
const pkg = await res.json()
|
||||
|
||||
if (res.ok) {
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
import { onMount } from "svelte"
|
||||
import ActionButton from "components/common/ActionButton.svelte"
|
||||
import IconButton from "components/common/IconButton.svelte"
|
||||
|
||||
import { get } from "builderStore/api"
|
||||
import Spinner from "components/common/Spinner.svelte"
|
||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||
|
||||
let promise = getApps()
|
||||
|
||||
async function getApps() {
|
||||
const res = await fetch(`/api/applications`)
|
||||
const res = await get("/api/applications")
|
||||
const json = await res.json()
|
||||
|
||||
if (res.ok) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"version": "0.0.32",
|
||||
"description": "Budibase CLI",
|
||||
"repository": "https://github.com/Budibase/Budibase",
|
||||
"homepage": "https://budibase.com",
|
||||
"homepage": "https://www.budibase.com",
|
||||
"main": "src/cli.js",
|
||||
"bin": {
|
||||
"budi": "bin/budi"
|
||||
|
|
|
@ -15,4 +15,7 @@ JWT_SECRET={{cookieKey1}}
|
|||
PORT=4001
|
||||
|
||||
# error level for koa-pino
|
||||
LOG_LEVEL=error
|
||||
LOG_LEVEL=error
|
||||
|
||||
# Budibase app directory
|
||||
BUDIBASE_DIR=~/.budibase
|
Before Width: | Height: | Size: 109 KiB |
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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 400 400" style="enable-background:new 0 0 400 400;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#6A78D1;}
|
||||
.st2{fill:#49C39E;}
|
||||
.st3{fill:#F2545B;}
|
||||
.st4{fill:#F5C26B;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M215,14.1l136.2,79.8c9.3,5.4,15,15.5,15,26.4v159.5c0,10.9-5.7,20.9-15,26.4L215,385.9
|
||||
c-9.3,5.4-20.7,5.4-30,0L48.8,306.2c-9.3-5.4-15-15.5-15-26.4V120.2c0-10.9,5.7-20.9,15-26.4L185,14.1
|
||||
C194.3,8.6,205.7,8.6,215,14.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M288.8,273.7l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6
|
||||
c3.6-1.9,8-1.9,11.6,0l83,43.6C297.1,258.3,297.1,269.4,288.8,273.7z"/>
|
||||
<path class="st2" d="M288.8,231.2l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6
|
||||
c3.6-1.9,8-1.9,11.6,0l83,43.6C297.1,215.7,297.1,226.9,288.8,231.2z"/>
|
||||
<path class="st3" d="M288.8,188.6l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6
|
||||
c3.6-1.9,8-1.9,11.6,0l83,43.6C297.1,173.1,297.1,184.3,288.8,188.6z"/>
|
||||
<path class="st4" d="M288.8,146l-83,43.6c-3.6,1.9-8,1.9-11.6,0l-83-43.6c-8.2-4.3-8.2-15.5,0-19.8l83-43.6c3.6-1.9,8-1.9,11.6,0
|
||||
l83,43.6C297.1,130.6,297.1,141.7,288.8,146z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 241 KiB |
Before Width: | Height: | Size: 381 KiB |
|
@ -5,8 +5,9 @@ const newid = require("../../db/newid")
|
|||
const env = require("../../environment")
|
||||
const instanceController = require("./instance")
|
||||
const { resolve, join } = require("path")
|
||||
const { copy, readJSON, writeJSON, exists } = require("fs-extra")
|
||||
const { copy, exists, readFile, writeFile } = require("fs-extra")
|
||||
const { exec } = require("child_process")
|
||||
const sqrl = require("squirrelly")
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
|
||||
|
@ -82,16 +83,27 @@ const createEmptyAppPackage = async (ctx, app) => {
|
|||
|
||||
await copy(templateFolder, newAppFolder)
|
||||
|
||||
const packageJsonPath = join(appsFolder, app._id, "package.json")
|
||||
const packageJson = await readJSON(packageJsonPath)
|
||||
|
||||
packageJson.name = npmFriendlyAppName(app.name)
|
||||
|
||||
await writeJSON(packageJsonPath, packageJson)
|
||||
await updateJsonFile(join(appsFolder, app._id, "package.json"), {
|
||||
name: npmFriendlyAppName(app.name),
|
||||
})
|
||||
await updateJsonFile(
|
||||
join(appsFolder, app._id, "pages", "main", "page.json"),
|
||||
app
|
||||
)
|
||||
await updateJsonFile(
|
||||
join(appsFolder, app._id, "pages", "unauthenticated", "page.json"),
|
||||
app
|
||||
)
|
||||
|
||||
return newAppFolder
|
||||
}
|
||||
|
||||
const updateJsonFile = async (filePath, app) => {
|
||||
const json = await readFile(filePath, "utf8")
|
||||
const newJson = sqrl.Render(json, app)
|
||||
await writeFile(filePath, newJson, "utf8")
|
||||
}
|
||||
|
||||
const runNpmInstall = async newAppFolder => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const cmd = `cd ${newAppFolder} && npm install`
|
||||
|
|
|
@ -10,6 +10,12 @@ exports.fetch = async function(ctx) {
|
|||
ctx.body = body.rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
exports.find = async function(ctx) {
|
||||
const db = new CouchDB(ctx.params.instanceId)
|
||||
const model = await db.get(ctx.params.id)
|
||||
ctx.body = model
|
||||
}
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const db = new CouchDB(ctx.params.instanceId)
|
||||
const newModel = {
|
||||
|
|
|
@ -13,7 +13,6 @@ exports.serveBuilder = async function(ctx) {
|
|||
}
|
||||
|
||||
exports.serveApp = async function(ctx) {
|
||||
// TODO: update homedir stuff to wherever budi is run
|
||||
// default to homedir
|
||||
const appPath = resolve(
|
||||
budibaseAppsDir(),
|
||||
|
@ -26,7 +25,6 @@ exports.serveApp = async function(ctx) {
|
|||
}
|
||||
|
||||
exports.serveComponentLibrary = async function(ctx) {
|
||||
// TODO: update homedir stuff to wherever budi is run
|
||||
// default to homedir
|
||||
let componentLibraryPath = resolve(
|
||||
budibaseAppsDir(),
|
||||
|
|
|
@ -38,6 +38,7 @@ router
|
|||
ctx.config = {
|
||||
latestPackagesFolder: budibaseAppsDir(),
|
||||
jwtSecret: env.JWT_SECRET,
|
||||
useAppRootPath: true,
|
||||
}
|
||||
ctx.isDev = env.NODE_ENV !== "production" && env.NODE_ENV !== "jest"
|
||||
await next()
|
||||
|
|
|
@ -43,6 +43,7 @@ router
|
|||
|
||||
router
|
||||
.get("/api/:instanceId/models", authorized(BUILDER), modelController.fetch)
|
||||
.get("/api/:instanceId/models/:id", authorized(BUILDER), modelController.find)
|
||||
.post("/api/:instanceId/models", authorized(BUILDER), modelController.create)
|
||||
// .patch("/api/:instanceId/models", controller.update)
|
||||
.delete(
|
||||
|
|
|
@ -22,6 +22,7 @@ exports.supertest = async () => {
|
|||
exports.defaultHeaders = {
|
||||
Accept: "application/json",
|
||||
Cookie: ["builder:token=test-admin-secret"],
|
||||
"user-agent": "Budibase Builder",
|
||||
}
|
||||
|
||||
exports.createModel = async (request, instanceId, model) => {
|
||||
|
|
|
@ -13,23 +13,34 @@ module.exports = async (ctx, next) => {
|
|||
return
|
||||
}
|
||||
|
||||
if (ctx.cookies.get("builder:token") === env.ADMIN_SECRET) {
|
||||
ctx.isAuthenticated = true
|
||||
ctx.isBuilder = true
|
||||
const appToken = ctx.cookies.get("budibase:token")
|
||||
const builderToken = ctx.cookies.get("builder:token")
|
||||
const isBuilderAgent = ctx.headers["user-agent"] === "Budibase Builder"
|
||||
|
||||
// all admin api access should auth with buildertoken and 'Budibase Builder user agent
|
||||
const shouldAuthAsBuilder = isBuilderAgent && builderToken
|
||||
|
||||
if (shouldAuthAsBuilder) {
|
||||
if (builderToken === env.ADMIN_SECRET) {
|
||||
ctx.isAuthenticated = true
|
||||
ctx.isBuilder = true
|
||||
} else {
|
||||
ctx.isAuthenticated = false
|
||||
ctx.isBuilder = false
|
||||
}
|
||||
|
||||
await next()
|
||||
return
|
||||
}
|
||||
|
||||
const token = ctx.cookies.get("budibase:token")
|
||||
|
||||
if (!token) {
|
||||
if (!appToken) {
|
||||
ctx.isAuthenticated = false
|
||||
await next()
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const jwtPayload = jwt.verify(token, ctx.config.jwtSecret)
|
||||
const jwtPayload = jwt.verify(appToken, ctx.config.jwtSecret)
|
||||
|
||||
ctx.user = {
|
||||
...jwtPayload,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "name",
|
||||
"name": "{{ name }}",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"title": "Test App",
|
||||
"title": "{{ name }}",
|
||||
"favicon": "./_shared/favicon.png",
|
||||
"stylesheets": [],
|
||||
"componentLibraries": ["@budibase/standard-components", "@budibase/materialdesign-components"],
|
||||
|
@ -9,8 +9,10 @@
|
|||
"_id": 0,
|
||||
"type": "div",
|
||||
"_styles": {
|
||||
"layout": {},
|
||||
"position": {}
|
||||
"active": {},
|
||||
"hover": {},
|
||||
"normal": {},
|
||||
"selected": {}
|
||||
},
|
||||
"_code": ""
|
||||
},
|
||||
|
|
|
@ -1,19 +1,45 @@
|
|||
{
|
||||
"title": "Test App",
|
||||
"favicon": "./_shared/favicon.png",
|
||||
"stylesheets": [],
|
||||
"componentLibraries": ["@budibase/standard-components", "@budibase/materialdesign-components"],
|
||||
"props" : {
|
||||
"_component": "@budibase/standard-components/container",
|
||||
"_children": [],
|
||||
"_id": 1,
|
||||
"type": "div",
|
||||
"_styles": {
|
||||
"layout": {},
|
||||
"position": {}
|
||||
},
|
||||
"_code": ""
|
||||
},
|
||||
"_css": "",
|
||||
"uiFunctions": ""
|
||||
"componentLibraries": [
|
||||
"@budibase/standard-components",
|
||||
"@budibase/materialdesign-components"
|
||||
],
|
||||
"title": "{{ name }}",
|
||||
"favicon": "./_shared/favicon.png",
|
||||
"stylesheets": [],
|
||||
"props": {
|
||||
"_component": "@budibase/standard-components/container",
|
||||
"_children": [
|
||||
{
|
||||
"_id": "686c252d-dbf2-4e28-9078-414ba4719759",
|
||||
"_component": "@budibase/standard-components/login",
|
||||
"_styles": {
|
||||
"normal": {},
|
||||
"hover": {},
|
||||
"active": {},
|
||||
"selected": {}
|
||||
},
|
||||
"_code": "",
|
||||
"loginRedirect": "",
|
||||
"usernameLabel": "Username",
|
||||
"passwordLabel": "Password",
|
||||
"loginButtonLabel": "Login",
|
||||
"buttonClass": "",
|
||||
"inputClass": "",
|
||||
"_children": [],
|
||||
"name": "{{ name }}",
|
||||
"logo": ""
|
||||
}
|
||||
],
|
||||
"_id": 1,
|
||||
"type": "div",
|
||||
"_styles": {
|
||||
"layout": {},
|
||||
"position": {}
|
||||
},
|
||||
"_code": "",
|
||||
"className": "",
|
||||
"onLoad": []
|
||||
},
|
||||
"_css": "",
|
||||
"uiFunctions": ""
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@ module.exports = async (config, appId, pageName, pkg) => {
|
|||
await savePageJson(appPath, pageName, pkg)
|
||||
}
|
||||
|
||||
const rootPath = (config, appname) =>
|
||||
config.useAppRootPath ? `/${appname}` : ""
|
||||
const rootPath = (config, appId) => (config.useAppRootPath ? `/${appId}` : "")
|
||||
|
||||
const copyClientLib = async (appPath, pageName) => {
|
||||
const sourcepath = require.resolve("@budibase/client")
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf8'>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
|
||||
<title>{{ title }}</title>
|
||||
<head>
|
||||
<meta charset='utf8'>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
|
||||
<title>{{ title }}</title>
|
||||
<link rel='icon' type='image/png' href='{{ favicon }}'>
|
||||
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
font-family: Roboto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
|
@ -30,13 +33,14 @@
|
|||
|
||||
<script src='{{ appRootPath }}/clientFrontendDefinition.js'></script>
|
||||
<script src='{{ appRootPath }}/budibase-client.js'></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body id="app">
|
||||
|
||||
|
||||
<script>
|
||||
loadBudibase();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -59,6 +59,7 @@
|
|||
"props": {
|
||||
"logo": "asset",
|
||||
"loginRedirect": "string",
|
||||
"name": "string",
|
||||
"usernameLabel": {
|
||||
"type": "string",
|
||||
"default": "Username"
|
||||
|
|
|
@ -20,17 +20,17 @@
|
|||
height: "400",
|
||||
dataFormat: "json",
|
||||
dataSource: {
|
||||
data: $store[model._id] || [],
|
||||
data: $store[model] || [],
|
||||
},
|
||||
}
|
||||
|
||||
async function fetchData() {
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/all_${model._id}/records`
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/views/all_${model}`
|
||||
const response = await _bb.api.get(FETCH_RECORDS_URL)
|
||||
if (response.status === 200) {
|
||||
const json = await response.json()
|
||||
store.update(state => {
|
||||
state[model._id] = json
|
||||
state[model] = json
|
||||
return state
|
||||
})
|
||||
} else {
|
||||
|
|
|
@ -8,19 +8,32 @@
|
|||
let username
|
||||
let password
|
||||
let newModel = {
|
||||
modelId: model._id,
|
||||
modelId: model,
|
||||
}
|
||||
let store = _bb.store
|
||||
let schema = {}
|
||||
let modelDef = {}
|
||||
|
||||
$: fields = Object.keys(model.schema)
|
||||
$: if (model && model.length !== 0) {
|
||||
fetchModel()
|
||||
}
|
||||
|
||||
$: fields = Object.keys(schema)
|
||||
|
||||
async function fetchModel() {
|
||||
const FETCH_MODEL_URL = `/api/${_instanceId}/models/${model}`
|
||||
const response = await _bb.api.get(FETCH_MODEL_URL)
|
||||
modelDef = await response.json()
|
||||
schema = modelDef.schema
|
||||
}
|
||||
|
||||
async function save() {
|
||||
const SAVE_RECORD_URL = `/api/${_instanceId}/records`
|
||||
const SAVE_RECORD_URL = `/api/${_instanceId}/${model}/records`
|
||||
const response = await _bb.api.post(SAVE_RECORD_URL, newModel)
|
||||
const json = await response.json()
|
||||
|
||||
store.update(state => {
|
||||
state[model._id] = [...state[model._id], json]
|
||||
state[model._id] = [...state[model], json]
|
||||
return state
|
||||
})
|
||||
}
|
||||
|
@ -46,14 +59,14 @@
|
|||
</script>
|
||||
|
||||
<form class="uk-form" on:submit|preventDefault>
|
||||
<h4>{model.name}</h4>
|
||||
<h4>{modelDef.name}</h4>
|
||||
<div>
|
||||
{#each fields as field}
|
||||
<div class="uk-margin">
|
||||
<label class="form-label" for="form-stacked-text">{field}</label>
|
||||
<input
|
||||
class="uk-input"
|
||||
type={model.schema[field].type === 'string' ? 'text' : model.schema[field].type}
|
||||
type={schema[field].type === 'string' ? 'text' : schema[field].type}
|
||||
on:change={handleInput(field)} />
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
let store = _bb.store
|
||||
|
||||
async function fetchData() {
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/all_${model._id}/records`
|
||||
if (!model || !model.length) return
|
||||
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/views/all_${model}`
|
||||
const response = await _bb.api.get(FETCH_RECORDS_URL)
|
||||
if (response.status === 200) {
|
||||
const json = await response.json()
|
||||
|
||||
store.update(state => {
|
||||
state[model._id] = json
|
||||
state[model] = json
|
||||
return state
|
||||
})
|
||||
} else {
|
||||
|
@ -24,7 +26,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
$: data = $store[model._id] || []
|
||||
$: data = $store[model] || []
|
||||
$: if (model) fetchData()
|
||||
|
||||
onMount(async () => {
|
||||
await fetchData()
|
||||
|
|
|
@ -10,13 +10,14 @@
|
|||
let store = _bb.store
|
||||
|
||||
async function fetchData() {
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/all_${model._id}/records`
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/views/all_${model}`
|
||||
|
||||
const response = await _bb.api.get(FETCH_RECORDS_URL)
|
||||
if (response.status === 200) {
|
||||
const json = await response.json()
|
||||
|
||||
store.update(state => {
|
||||
state[model._id] = json
|
||||
state[model] = json
|
||||
return state
|
||||
})
|
||||
|
||||
|
@ -26,7 +27,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
$: data = $store[model._id] || []
|
||||
$: data = $store[model] || []
|
||||
$: if (model) fetchData()
|
||||
|
||||
onMount(async () => {
|
||||
await fetchData()
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
$: target = openInNewTab ? "_blank" : "_self"
|
||||
</script>
|
||||
|
||||
<a href={url} bind:this={anchorElement} {target}>{text}</a>
|
||||
<a href={_bb.relativeUrl(url)} bind:this={anchorElement} {target}>{text}</a>
|
||||
|
||||
<style>
|
||||
.textDecoration {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<script>
|
||||
import Button from "./Button.svelte"
|
||||
|
||||
export let usernameLabel = "Username"
|
||||
export let passwordLabel = "Password"
|
||||
export let loginButtonLabel = "Login"
|
||||
export let logo = ""
|
||||
export let name = ""
|
||||
export let buttonClass = ""
|
||||
export let inputClass = ""
|
||||
|
||||
|
@ -51,14 +50,23 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<h1 class="header-content">Log in to {name}</h1>
|
||||
|
||||
<div class="form-root">
|
||||
<div class="label">{usernameLabel}</div>
|
||||
<div class="control">
|
||||
<input bind:value={username} type="text" class={_inputClass} />
|
||||
<input
|
||||
bind:value={username}
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
class={_inputClass} />
|
||||
</div>
|
||||
<div class="label">{passwordLabel}</div>
|
||||
|
||||
<div class="control">
|
||||
<input bind:value={password} type="password" class={_inputClass} />
|
||||
<input
|
||||
bind:value={password}
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
class={_inputClass} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -77,28 +85,42 @@
|
|||
<style>
|
||||
.root {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: [left] 1fr [middle] auto [right] 1fr;
|
||||
grid-template-rows: [top] 1fr [center] auto [bottom] 1fr;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-column-start: middle;
|
||||
grid-row-start: center;
|
||||
width: 400px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.logo-container > img {
|
||||
max-width: 100%;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.login-button-container {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
margin-top: 6px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
font-family: Inter;
|
||||
font-weight: 700;
|
||||
color: #1f1f1f;
|
||||
font-size: 48px;
|
||||
line-height: 72px;
|
||||
margin-bottom: 30px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-feature-settings: "case" "rlig" "calt" 0;
|
||||
}
|
||||
|
||||
.incorrect-details-panel {
|
||||
|
@ -114,48 +136,55 @@
|
|||
}
|
||||
|
||||
.form-root {
|
||||
display: grid;
|
||||
grid-template-columns: [label] auto [control] 1fr; /* [overflow] auto;*/
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.label {
|
||||
grid-column-start: label;
|
||||
padding: 5px 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.control {
|
||||
grid-column-start: control;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.default-input {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
padding: 0.4em;
|
||||
margin: 0 0 0.5em 0;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
padding: 6px 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.default-button {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
padding: 0.4em;
|
||||
.default-input {
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
color: #393c44;
|
||||
padding: 2px 6px 2px 12px;
|
||||
margin: 0 0 0.5em 0;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
color: #000333;
|
||||
border: 0.5px solid #d8d8d8;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
transition: border-color 100ms ease-in 0s;
|
||||
outline-color: #797979;
|
||||
}
|
||||
|
||||
.default-button {
|
||||
font-family: Inter;
|
||||
font-size: 16px;
|
||||
padding: 0.4em;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
background-color: #393c44;
|
||||
outline: none;
|
||||
width: 300px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease 0s;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.default-button:active {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.default-button:focus {
|
||||
border-color: #f9f9f9;
|
||||
.default-button:hover {
|
||||
background-color: white;
|
||||
border-color: #393c44;
|
||||
color: #393c44;
|
||||
}
|
||||
</style>
|
||||
|
|