Merge branch 'develop' of github.com:Budibase/budibase into feature/json-backend
This commit is contained in:
commit
4903b06e4c
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/auth",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"description": "Authentication middlewares for budibase builder and apps",
|
||||
"main": "src/index.js",
|
||||
"author": "Budibase",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"license": "AGPL-3.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -65,10 +65,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "^0.9.185-alpha.19",
|
||||
"@budibase/client": "^0.9.185-alpha.19",
|
||||
"@budibase/bbui": "^0.9.185-alpha.20",
|
||||
"@budibase/client": "^0.9.185-alpha.20",
|
||||
"@budibase/colorpicker": "1.1.2",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.19",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.20",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
ModalContent,
|
||||
Context,
|
||||
Modal,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
|
@ -26,7 +27,6 @@
|
|||
SWITCHABLE_TYPES,
|
||||
} from "constants/backend"
|
||||
import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
import ValuesList from "components/common/ValuesList.svelte"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import { truncate } from "lodash"
|
||||
|
@ -76,13 +76,8 @@
|
|||
$: invalid =
|
||||
!field.name ||
|
||||
(field.type === LINK_TYPE && !field.tableId) ||
|
||||
Object.keys($tables.draft?.schema ?? {}).some(
|
||||
key => key !== originalName && key === field.name
|
||||
) ||
|
||||
columnNameInvalid
|
||||
$: columnNameInvalid = PROHIBITED_COLUMN_NAMES.some(
|
||||
name => field.name === name
|
||||
)
|
||||
Object.keys(errors).length !== 0
|
||||
$: errors = checkErrors(field)
|
||||
|
||||
// used to select what different options can be displayed for column type
|
||||
$: canBeSearched =
|
||||
|
@ -111,6 +106,7 @@
|
|||
if (field.type === AUTO_TYPE) {
|
||||
field = buildAutoColumn($tables.draft.name, field.name, field.subtype)
|
||||
}
|
||||
try {
|
||||
await tables.saveField({
|
||||
originalName,
|
||||
field,
|
||||
|
@ -118,6 +114,9 @@
|
|||
indexes,
|
||||
})
|
||||
dispatch("updatecolumns")
|
||||
} catch (err) {
|
||||
notifications.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
function deleteColumn() {
|
||||
|
@ -267,6 +266,31 @@
|
|||
fieldToCheck.constraints.numericality = {}
|
||||
}
|
||||
}
|
||||
|
||||
function checkErrors(fieldInfo) {
|
||||
function inUse(tbl, column, ogName = null) {
|
||||
return Object.keys(tbl?.schema || {}).some(
|
||||
key => key !== ogName && key === column
|
||||
)
|
||||
}
|
||||
const newError = {}
|
||||
if (PROHIBITED_COLUMN_NAMES.some(name => fieldInfo.name === name)) {
|
||||
newError.name = `${PROHIBITED_COLUMN_NAMES.join(
|
||||
", "
|
||||
)} are not allowed as column names`
|
||||
} else if (inUse($tables.draft, fieldInfo.name, originalName)) {
|
||||
newError.name = `Column name already in use.`
|
||||
}
|
||||
if (fieldInfo.fieldName && fieldInfo.tableId) {
|
||||
const relatedTable = $tables.list.find(
|
||||
tbl => tbl._id === fieldInfo.tableId
|
||||
)
|
||||
if (inUse(relatedTable, fieldInfo.fieldName)) {
|
||||
newError.relatedName = `Column name already in use in table ${relatedTable.name}`
|
||||
}
|
||||
}
|
||||
return newError
|
||||
}
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
|
@ -279,9 +303,7 @@
|
|||
label="Name"
|
||||
bind:value={field.name}
|
||||
disabled={uneditable || (linkEditDisabled && field.type === LINK_TYPE)}
|
||||
error={columnNameInvalid
|
||||
? `${PROHIBITED_COLUMN_NAMES.join(", ")} are not allowed as column names`
|
||||
: ""}
|
||||
error={errors?.name}
|
||||
/>
|
||||
|
||||
<Select
|
||||
|
@ -390,6 +412,7 @@
|
|||
disabled={linkEditDisabled}
|
||||
label={`Column name in other table`}
|
||||
bind:value={field.fieldName}
|
||||
error={errors.relatedName}
|
||||
/>
|
||||
{:else if field.type === FORMULA_TYPE}
|
||||
<ModalBindableInput
|
||||
|
|
|
@ -71,6 +71,9 @@
|
|||
if ($touched.toCol && !toRelate.name) {
|
||||
errors.toCol = colNotSet
|
||||
}
|
||||
if ($touched.primary && !fromPrimary) {
|
||||
errors.primary = "Please pick the primary key"
|
||||
}
|
||||
// currently don't support relationships back onto the table itself, needs to relate out
|
||||
const tableError = "From/to/through tables must be different"
|
||||
if (fromTable && (fromTable === toTable || fromTable === throughTable)) {
|
||||
|
@ -95,6 +98,16 @@
|
|||
return errors
|
||||
}
|
||||
|
||||
let fromPrimary
|
||||
$: {
|
||||
if (!fromPrimary && fromTable) {
|
||||
fromPrimary = fromTable.primary[0]
|
||||
}
|
||||
}
|
||||
$: isManyToMany =
|
||||
fromRelationship?.relationshipType === RelationshipTypes.MANY_TO_MANY
|
||||
$: isManyToOne =
|
||||
fromRelationship?.relationshipType === RelationshipTypes.MANY_TO_ONE
|
||||
$: tableOptions = plusTables.map(table => ({
|
||||
label: table.name,
|
||||
value: table._id,
|
||||
|
@ -179,13 +192,13 @@
|
|||
// foreignKey is what is linking out of the current table.
|
||||
relateFrom = {
|
||||
...relateFrom,
|
||||
foreignKey: fromTable.primary[0],
|
||||
foreignKey: fromPrimary,
|
||||
}
|
||||
relateTo = {
|
||||
...relateTo,
|
||||
relationshipType: RelationshipTypes.ONE_TO_MANY,
|
||||
foreignKey: relateFrom.fieldName,
|
||||
fieldName: fromTable.primary[0],
|
||||
fieldName: fromPrimary,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,6 +277,15 @@
|
|||
bind:error={errors.from}
|
||||
bind:value={toRelationship.tableId}
|
||||
/>
|
||||
{#if isManyToOne && fromTable}
|
||||
<Select
|
||||
label={`Primary Key (${fromTable?.name})`}
|
||||
options={Object.keys(fromTable?.schema)}
|
||||
on:change={() => ($touched.primary = true)}
|
||||
bind:error={errors.primary}
|
||||
bind:value={fromPrimary}
|
||||
/>
|
||||
{/if}
|
||||
<Select
|
||||
label={"Select to table"}
|
||||
options={tableOptions}
|
||||
|
@ -271,7 +293,7 @@
|
|||
bind:error={errors.to}
|
||||
bind:value={fromRelationship.tableId}
|
||||
/>
|
||||
{#if fromRelationship?.relationshipType === RelationshipTypes.MANY_TO_MANY}
|
||||
{#if isManyToMany}
|
||||
<Select
|
||||
label={"Through"}
|
||||
options={tableOptions}
|
||||
|
@ -295,7 +317,7 @@
|
|||
bind:value={fromRelationship.throughFrom}
|
||||
/>
|
||||
{/if}
|
||||
{:else if fromRelationship?.relationshipType && toTable}
|
||||
{:else if isManyToOne && toTable}
|
||||
<Select
|
||||
label={`Foreign Key (${toTable?.name})`}
|
||||
options={Object.keys(toTable?.schema).filter(
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
<script>
|
||||
import { store } from "builderStore"
|
||||
import { tables } from "stores/backend"
|
||||
import { ModalContent, Body, Detail, Layout, Icon } from "@budibase/bbui"
|
||||
import {
|
||||
ModalContent,
|
||||
Body,
|
||||
Detail,
|
||||
Layout,
|
||||
Icon,
|
||||
ProgressCircle,
|
||||
} from "@budibase/bbui"
|
||||
import getTemplates from "builderStore/store/screenTemplates"
|
||||
|
||||
export let selectedScreens = []
|
||||
export let chooseModal
|
||||
export let save
|
||||
|
||||
export let showProgressCircle = false
|
||||
const blankScreen = "createFromScratch"
|
||||
|
||||
$: blankSelected = selectedScreens?.length === 1
|
||||
|
@ -27,6 +34,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div style="overflow-y: auto; max-height: 1000px">
|
||||
<ModalContent
|
||||
title="Add screens"
|
||||
confirmText="Add Screens"
|
||||
|
@ -50,11 +58,15 @@
|
|||
class:disabled={autoSelected}
|
||||
>
|
||||
<div data-cy="blank-screen" class="content">
|
||||
<Body size="S">Blank</Body>
|
||||
<div class="text">Blank</div>
|
||||
</div>
|
||||
<div style="color: var(--spectrum-global-color-green-600); float: right">
|
||||
<div
|
||||
style="color: var(--spectrum-global-color-green-600); float: right"
|
||||
>
|
||||
{#if selectedScreens.find(x => x.id === blankScreen)}
|
||||
<div class="checkmark-spacing">
|
||||
<Icon size="S" name="CheckmarkCircleOutline" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -63,42 +75,67 @@
|
|||
{#each $tables.list.filter(table => table._id !== "ta_users") as table}
|
||||
<div
|
||||
class:disabled={blankSelected}
|
||||
class:selected={selectedScreens.find(x => x.name.includes(table.name))}
|
||||
class:selected={selectedScreens.find(x =>
|
||||
x.name.includes(table.name)
|
||||
)}
|
||||
on:click={() => toggleScreenSelection(table)}
|
||||
class="item"
|
||||
>
|
||||
<div class="content">
|
||||
{table.name}
|
||||
<div class="text">{table.name}</div>
|
||||
</div>
|
||||
<div
|
||||
style="color: var(--spectrum-global-color-green-600); float: right"
|
||||
>
|
||||
{#if selectedScreens.find(x => x.name.includes(table.name))}
|
||||
<div class="checkmark-spacing">
|
||||
<Icon size="S" name="CheckmarkCircleOutline" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</Layout>
|
||||
<div slot="footer">
|
||||
{#if showProgressCircle}
|
||||
<div class="footer-progress"><ProgressCircle size="S" /></div>
|
||||
{/if}
|
||||
</div>
|
||||
</ModalContent>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.disabled {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
.checkmark-spacing {
|
||||
margin-right: var(--spacing-m);
|
||||
}
|
||||
|
||||
.content {
|
||||
letter-spacing: 0px;
|
||||
}
|
||||
|
||||
.footer-progress {
|
||||
margin-top: var(--spacing-s);
|
||||
}
|
||||
|
||||
.text {
|
||||
font-weight: 600;
|
||||
margin-left: var(--spacing-m);
|
||||
font-size: 14px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.item {
|
||||
cursor: pointer;
|
||||
grid-gap: var(--spectrum-alias-grid-margin-xsmall);
|
||||
padding: var(--spectrum-alias-item-padding-s);
|
||||
background: var(--background);
|
||||
background: var(--spectrum-alias-background-color-primary);
|
||||
transition: 0.3s all;
|
||||
border: solid var(--spectrum-alias-border-color);
|
||||
border-radius: 2px;
|
||||
border: 1px solid #e7e7e7;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
border-width: 1px;
|
||||
display: flex;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { ModalContent, Input } from "@budibase/bbui"
|
||||
import { ModalContent, Input, ProgressCircle } from "@budibase/bbui"
|
||||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
||||
import { selectedAccessRole, allScreens } from "builderStore"
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
|||
export let url
|
||||
export let chooseModal
|
||||
export let save
|
||||
export let showProgressCircle = false
|
||||
|
||||
let routeError
|
||||
let roleId = $selectedAccessRole || "BASIC"
|
||||
|
||||
|
@ -48,4 +50,15 @@
|
|||
bind:value={url}
|
||||
on:change={routeChanged}
|
||||
/>
|
||||
<div slot="footer">
|
||||
{#if showProgressCircle}
|
||||
<div class="footer-progress"><ProgressCircle size="S" /></div>
|
||||
{/if}
|
||||
</div>
|
||||
</ModalContent>
|
||||
|
||||
<style>
|
||||
.footer-progress {
|
||||
margin-top: var(--spacing-s);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,32 +12,36 @@
|
|||
let screenName = ""
|
||||
let url = ""
|
||||
let selectedScreens = []
|
||||
|
||||
let roleId = $selectedAccessRole || "BASIC"
|
||||
|
||||
let showProgressCircle = false
|
||||
let routeError
|
||||
let createdScreens = []
|
||||
$: {
|
||||
selectedScreens?.forEach(screen => {
|
||||
createdScreens = [...createdScreens, screen.create()]
|
||||
})
|
||||
|
||||
const createScreens = async () => {
|
||||
for (let screen of selectedScreens) {
|
||||
let test = screen.create()
|
||||
createdScreens.push(test)
|
||||
}
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
showProgressCircle = true
|
||||
await createScreens()
|
||||
for (let screen of createdScreens) {
|
||||
await saveScreens(screen)
|
||||
}
|
||||
|
||||
await store.actions.routing.fetch()
|
||||
selectedScreens = []
|
||||
createdScreens = []
|
||||
screenName = ""
|
||||
url = ""
|
||||
showProgressCircle = false
|
||||
}
|
||||
const saveScreens = async draftScreen => {
|
||||
let existingScreenCount = $store.screens.filter(
|
||||
s => s.props._instanceName == draftScreen.props._instanceName
|
||||
).length
|
||||
|
||||
if (existingScreenCount > 0) {
|
||||
let oldUrlArr = draftScreen.routing.route.split("/")
|
||||
oldUrlArr[1] = `${oldUrlArr[1]}-${existingScreenCount + 1}`
|
||||
|
@ -86,6 +90,7 @@
|
|||
selectedScreens = []
|
||||
screenName = ""
|
||||
url = ""
|
||||
createdScreens = []
|
||||
})
|
||||
|
||||
export const showModal = () => {
|
||||
|
@ -109,9 +114,20 @@
|
|||
</script>
|
||||
|
||||
<Modal bind:this={newScreenModal}>
|
||||
<NewScreenModal bind:selectedScreens {save} {chooseModal} />
|
||||
<NewScreenModal
|
||||
bind:selectedScreens
|
||||
{showProgressCircle}
|
||||
{save}
|
||||
{chooseModal}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={screenDetailsModal}>
|
||||
<ScreenDetailsModal bind:screenName bind:url {save} {chooseModal} />
|
||||
<ScreenDetailsModal
|
||||
bind:screenName
|
||||
bind:url
|
||||
{showProgressCircle}
|
||||
{save}
|
||||
{chooseModal}
|
||||
/>
|
||||
</Modal>
|
||||
|
|
|
@ -66,6 +66,9 @@ export function createTablesStore() {
|
|||
}
|
||||
|
||||
const response = await api.post(`/api/tables`, updatedTable)
|
||||
if (response.status !== 200) {
|
||||
throw (await response.json()).message
|
||||
}
|
||||
const savedTable = await response.json()
|
||||
await fetch()
|
||||
if (table.type === "external") {
|
||||
|
|
|
@ -42,7 +42,7 @@ describe("Tables Store", () => {
|
|||
})
|
||||
|
||||
it("saving a table also selects it", async () => {
|
||||
api.post.mockReturnValue({ json: () => SAVE_TABLES_RESPONSE})
|
||||
api.post.mockReturnValue({ status: 200, json: () => SAVE_TABLES_RESPONSE})
|
||||
|
||||
await store.save(A_TABLE)
|
||||
|
||||
|
@ -50,7 +50,7 @@ describe("Tables Store", () => {
|
|||
})
|
||||
|
||||
it("saving the table returns a response", async () => {
|
||||
api.post.mockReturnValue({ json: () => SAVE_TABLES_RESPONSE})
|
||||
api.post.mockReturnValue({ status: 200, json: () => SAVE_TABLES_RESPONSE})
|
||||
|
||||
const response = await store.save(A_TABLE)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,9 +19,9 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "^0.9.185-alpha.19",
|
||||
"@budibase/bbui": "^0.9.185-alpha.20",
|
||||
"@budibase/standard-components": "^0.9.139",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.19",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.20",
|
||||
"regexparam": "^1.3.0",
|
||||
"shortid": "^2.2.15",
|
||||
"svelte-spa-router": "^3.0.5"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.js",
|
||||
"repository": {
|
||||
|
@ -68,9 +68,9 @@
|
|||
"author": "Budibase",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@budibase/auth": "^0.9.185-alpha.19",
|
||||
"@budibase/client": "^0.9.185-alpha.19",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.19",
|
||||
"@budibase/auth": "^0.9.185-alpha.20",
|
||||
"@budibase/client": "^0.9.185-alpha.20",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.20",
|
||||
"@bull-board/api": "^3.7.0",
|
||||
"@bull-board/koa": "^3.7.0",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "0.9.185-alpha.19",
|
||||
"version": "0.9.185-alpha.20",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.js",
|
||||
"repository": {
|
||||
|
@ -29,8 +29,8 @@
|
|||
"author": "Budibase",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@budibase/auth": "^0.9.185-alpha.19",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.19",
|
||||
"@budibase/auth": "^0.9.185-alpha.20",
|
||||
"@budibase/string-templates": "^0.9.185-alpha.20",
|
||||
"@koa/router": "^8.0.0",
|
||||
"@sentry/node": "^6.0.0",
|
||||
"@techpass/passport-openidconnect": "^0.3.0",
|
||||
|
|
Loading…
Reference in New Issue