Merge branch 'master' of github.com:Budibase/budibase into develop
This commit is contained in:
commit
b9caf0aef5
40 changed files with 241 additions and 199 deletions
|
@ -84,6 +84,8 @@ spec:
|
|||
value: {{ .Values.services.objectStore.appsBucketName | quote }}
|
||||
- name: GLOBAL_CLOUD_BUCKET_NAME
|
||||
value: {{ .Values.services.objectStore.globalBucketName | quote }}
|
||||
- name: BACKUPS_BUCKET_NAME
|
||||
value: {{ .Values.services.objectStore.backupsBucketName | quote }}
|
||||
- name: PORT
|
||||
value: {{ .Values.services.apps.port | quote }}
|
||||
{{ if .Values.services.worker.publicApiRateLimitPerSecond }}
|
||||
|
|
|
@ -83,6 +83,8 @@ spec:
|
|||
value: {{ .Values.services.objectStore.appsBucketName | quote }}
|
||||
- name: GLOBAL_CLOUD_BUCKET_NAME
|
||||
value: {{ .Values.services.objectStore.globalBucketName | quote }}
|
||||
- name: BACKUPS_BUCKET_NAME
|
||||
value: {{ .Values.services.objectStore.backupsBucketName | quote }}
|
||||
- name: PORT
|
||||
value: {{ .Values.services.worker.port | quote }}
|
||||
- name: MULTI_TENANCY
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -20,7 +20,7 @@
|
|||
"test:watch": "jest --watchAll"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/types": "2.0.40-alpha.4",
|
||||
"@budibase/types": "^2.1.11",
|
||||
"@shopify/jest-koa-mocks": "5.0.1",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-sdk": "2.1030.0",
|
||||
|
|
|
@ -24,10 +24,15 @@ import {
|
|||
} from "./middleware"
|
||||
import { invalidateUser } from "./cache/user"
|
||||
import { User } from "@budibase/types"
|
||||
import { logAlert } from "./logging"
|
||||
|
||||
// Strategies
|
||||
passport.use(new LocalStrategy(local.options, local.authenticate))
|
||||
passport.use(new JwtStrategy(jwt.options, jwt.authenticate))
|
||||
if (jwt.options.secretOrKey) {
|
||||
passport.use(new JwtStrategy(jwt.options, jwt.authenticate))
|
||||
} else {
|
||||
logAlert("No JWT Secret supplied, cannot configure JWT strategy")
|
||||
}
|
||||
|
||||
passport.serializeUser((user: User, done: any) => done(null, user))
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import events from "events"
|
||||
import { timeout } from "../../utils"
|
||||
|
||||
/**
|
||||
* Bull works with a Job wrapper around all messages that contains a lot more information about
|
||||
|
@ -27,6 +28,7 @@ class InMemoryQueue {
|
|||
_opts?: any
|
||||
_messages: any[]
|
||||
_emitter: EventEmitter
|
||||
_runCount: number
|
||||
/**
|
||||
* The constructor the queue, exactly the same as that of Bulls.
|
||||
* @param {string} name The name of the queue which is being configured.
|
||||
|
@ -38,6 +40,7 @@ class InMemoryQueue {
|
|||
this._opts = opts
|
||||
this._messages = []
|
||||
this._emitter = new events.EventEmitter()
|
||||
this._runCount = 0
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,6 +62,7 @@ class InMemoryQueue {
|
|||
if (resp.then != null) {
|
||||
await resp
|
||||
}
|
||||
this._runCount++
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -122,6 +126,15 @@ class InMemoryQueue {
|
|||
on() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
async waitForCompletion() {
|
||||
const currentCount = this._runCount
|
||||
let increased = false
|
||||
do {
|
||||
await timeout(50)
|
||||
increased = this._runCount > currentCount
|
||||
} while (!increased)
|
||||
}
|
||||
}
|
||||
|
||||
export = InMemoryQueue
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,7 +38,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
|
||||
"@budibase/string-templates": "2.0.40-alpha.4",
|
||||
"@budibase/string-templates": "^2.1.11",
|
||||
"@spectrum-css/actionbutton": "^1.0.1",
|
||||
"@spectrum-css/actiongroup": "^1.0.1",
|
||||
"@spectrum-css/avatar": "^3.0.2",
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
let selectedImageIdx = 0
|
||||
let fileDragged = false
|
||||
let selectedUrl
|
||||
let fileInput
|
||||
$: selectedImage = value?.[selectedImageIdx] ?? null
|
||||
$: fileCount = value?.length ?? 0
|
||||
$: isImage =
|
||||
|
@ -102,6 +103,7 @@
|
|||
await deleteAttachments(
|
||||
value.filter((x, idx) => idx === selectedImageIdx).map(item => item.key)
|
||||
)
|
||||
fileInput.value = ""
|
||||
}
|
||||
selectedImageIdx = 0
|
||||
}
|
||||
|
@ -234,6 +236,7 @@
|
|||
type="file"
|
||||
multiple
|
||||
accept={extensions}
|
||||
bind:this={fileInput}
|
||||
on:change={handleFile}
|
||||
/>
|
||||
<svg
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import Picker from "./Picker.svelte"
|
||||
import { createEventDispatcher, onMount } from "svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let value = []
|
||||
export let id = null
|
||||
|
@ -16,29 +16,6 @@
|
|||
export let autoWidth = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const parseValues = value => {
|
||||
return Array.isArray(value)
|
||||
? value.reduce((acc, entry) => {
|
||||
if (typeof ele === "string" && entry.trim() === "") {
|
||||
return acc
|
||||
}
|
||||
let processedOption = String(entry)
|
||||
if (options.indexOf(processedOption) > -1) {
|
||||
acc.push(processedOption)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
: []
|
||||
}
|
||||
let loaded = false
|
||||
|
||||
$: combinedValues = value ? [...value].concat(options) : []
|
||||
$: superSet = new Set(combinedValues)
|
||||
|
||||
$: if (loaded && options.length != superSet.size) {
|
||||
// ensure that the values being pushed in are valid.
|
||||
dispatch("change", parseValues(value))
|
||||
}
|
||||
|
||||
$: selectedLookupMap = getSelectedLookupMap(value)
|
||||
$: optionLookupMap = getOptionLookupMap(options)
|
||||
|
@ -95,10 +72,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
loaded = true
|
||||
})
|
||||
</script>
|
||||
|
||||
<Picker
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
const onPickPrimary = newValue => {
|
||||
dispatch("pickprimary", newValue)
|
||||
primaryOpen = false
|
||||
dispatch("closed")
|
||||
}
|
||||
|
||||
const onClearPrimary = () => {
|
||||
|
@ -92,6 +93,7 @@
|
|||
if (primaryOpen) {
|
||||
event.stopPropagation()
|
||||
primaryOpen = false
|
||||
dispatch("closed")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,5 +128,6 @@
|
|||
on:blur
|
||||
on:focus
|
||||
on:keyup
|
||||
on:closed
|
||||
/>
|
||||
</Field>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -71,10 +71,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.0.40-alpha.4",
|
||||
"@budibase/client": "2.0.40-alpha.4",
|
||||
"@budibase/frontend-core": "2.0.40-alpha.4",
|
||||
"@budibase/string-templates": "2.0.40-alpha.4",
|
||||
"@budibase/bbui": "^2.1.11",
|
||||
"@budibase/client": "^2.1.11",
|
||||
"@budibase/frontend-core": "^2.1.11",
|
||||
"@budibase/string-templates": "^2.1.11",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
// run the validation whenever the config changes
|
||||
$: validation.check(config)
|
||||
// dispatch the validation result
|
||||
$: dispatch("valid", $validation.valid)
|
||||
$: dispatch("valid", Object.keys($validation.errors).length === 0)
|
||||
|
||||
let addButton
|
||||
|
||||
|
|
|
@ -132,7 +132,20 @@
|
|||
config={integrationInfo.extra}
|
||||
/>
|
||||
{/if}
|
||||
<BindingBuilder bind:queryBindings={query.parameters} bindable={false} />
|
||||
{#key query.parameters}
|
||||
<BindingBuilder
|
||||
queryBindings={query.parameters}
|
||||
bindable={false}
|
||||
on:change={e => {
|
||||
query.parameters = e.detail.map(binding => {
|
||||
return {
|
||||
name: binding.name,
|
||||
default: binding.value,
|
||||
}
|
||||
})
|
||||
}}
|
||||
/>
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
{#if shouldShowQueryConfig}
|
||||
|
|
|
@ -44,14 +44,7 @@
|
|||
valuePlaceholder="Default"
|
||||
bindings={[...userBindings]}
|
||||
bindingDrawerLeft="260px"
|
||||
on:change={e => {
|
||||
queryBindings = e.detail.map(binding => {
|
||||
return {
|
||||
name: binding.name,
|
||||
default: binding.value,
|
||||
}
|
||||
})
|
||||
}}
|
||||
on:change
|
||||
/>
|
||||
</div>
|
||||
</Layout>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
} from "@budibase/bbui"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import CreateRestoreModal from "./CreateRestoreModal.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { createEventDispatcher, onMount } from "svelte"
|
||||
|
||||
export let row
|
||||
|
||||
|
@ -49,6 +49,10 @@
|
|||
async function downloadExport() {
|
||||
window.open(`/api/apps/${row.appId}/backups/${row._id}/file`, "_blank")
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
name = row.name
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="cell">
|
||||
|
@ -62,7 +66,7 @@
|
|||
<MenuItem on:click={deleteDialog.show} icon="Delete">Delete</MenuItem>
|
||||
<MenuItem on:click={downloadExport} icon="Download">Download</MenuItem>
|
||||
{/if}
|
||||
<MenuItem on:click={updateDialog.show} icon="Edit">Update</MenuItem>
|
||||
<MenuItem on:click={updateDialog.show} icon="Edit">Rename</MenuItem>
|
||||
</ActionMenu>
|
||||
</div>
|
||||
|
||||
|
@ -100,7 +104,7 @@
|
|||
title="Update Backup"
|
||||
warning={false}
|
||||
>
|
||||
<Input onlabel="Backup name" placeholder={row.name} bind:value={name} />
|
||||
<Input onlabel="Backup name" bind:value={name} />
|
||||
</ConfirmDialog>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -21,13 +21,14 @@
|
|||
import AppSizeRenderer from "./AppSizeRenderer.svelte"
|
||||
import CreateBackupModal from "./CreateBackupModal.svelte"
|
||||
import ActionsRenderer from "./ActionsRenderer.svelte"
|
||||
import DateRenderer from "./DateRenderer.svelte"
|
||||
import DateRenderer from "components/common/renderers/DateTimeRenderer.svelte"
|
||||
import UserRenderer from "./UserRenderer.svelte"
|
||||
import StatusRenderer from "./StatusRenderer.svelte"
|
||||
import TypeRenderer from "./TypeRenderer.svelte"
|
||||
import NameRenderer from "./NameRenderer.svelte"
|
||||
import BackupsDefault from "assets/backups-default.png"
|
||||
import { BackupTrigger, BackupType } from "constants/backend/backups"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
export let app
|
||||
|
||||
let backupData = null
|
||||
|
@ -36,30 +37,34 @@
|
|||
let filterOpt = null
|
||||
let startDate = null
|
||||
let endDate = null
|
||||
let filters = getFilters()
|
||||
let loaded = false
|
||||
let filters = [
|
||||
{
|
||||
label: "Manual backup",
|
||||
value: { type: BackupType.BACKUP, trigger: BackupTrigger.MANUAL },
|
||||
},
|
||||
{
|
||||
label: "Published backup",
|
||||
value: { type: BackupType.BACKUP, trigger: BackupTrigger.PUBLISH },
|
||||
},
|
||||
{
|
||||
label: "Scheduled backup",
|
||||
value: { type: BackupType.BACKUP, trigger: BackupTrigger.SCHEDULED },
|
||||
},
|
||||
{
|
||||
label: "Pre-restore backup",
|
||||
value: { type: BackupType.BACKUP, trigger: BackupTrigger.RESTORING },
|
||||
},
|
||||
{
|
||||
label: "Manual restore",
|
||||
value: { type: BackupType.RESTORE, trigger: BackupTrigger.MANUAL },
|
||||
},
|
||||
]
|
||||
|
||||
$: page = $pageInfo.page
|
||||
$: fetchBackups(filterOpt, page, startDate, endDate)
|
||||
|
||||
function getFilters() {
|
||||
const options = []
|
||||
let types = ["backup"]
|
||||
let triggers = ["manual", "publish", "scheduled", "restoring"]
|
||||
for (let type of types) {
|
||||
for (let trigger of triggers) {
|
||||
let label = `${trigger} ${type}`
|
||||
label = label.charAt(0).toUpperCase() + label?.slice(1)
|
||||
options.push({ label, value: { type, trigger } })
|
||||
}
|
||||
}
|
||||
options.push({
|
||||
label: `Manual restore`,
|
||||
value: { type: "restore", trigger: "manual" },
|
||||
})
|
||||
return options
|
||||
}
|
||||
|
||||
const schema = {
|
||||
let schema = {
|
||||
type: {
|
||||
displayName: "Type",
|
||||
width: "auto",
|
||||
|
@ -97,6 +102,7 @@
|
|||
{ column: "createdBy", component: UserRenderer },
|
||||
{ column: "status", component: StatusRenderer },
|
||||
{ column: "type", component: TypeRenderer },
|
||||
{ column: "name", component: NameRenderer },
|
||||
]
|
||||
|
||||
function flattenBackups(backups) {
|
||||
|
@ -260,7 +266,7 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="table">
|
||||
<Table
|
||||
{schema}
|
||||
disableSorting
|
||||
|
@ -308,7 +314,7 @@
|
|||
}
|
||||
|
||||
.select {
|
||||
flex-basis: 150px;
|
||||
flex-basis: 100px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
|
@ -342,4 +348,8 @@
|
|||
display: flex;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
|
||||
.table {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<script>
|
||||
import DateTimeRenderer from "components/common/renderers/DateTimeRenderer.svelte"
|
||||
import dayjs from "dayjs"
|
||||
import relativeTime from "dayjs/plugin/relativeTime"
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export let value
|
||||
$: timeSince = dayjs(value).fromNow()
|
||||
</script>
|
||||
|
||||
<div class="cell">
|
||||
{timeSince} - <DateTimeRenderer {value} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.cell {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: var(--spacing-m);
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,8 @@
|
|||
<script>
|
||||
import { truncate } from "lodash"
|
||||
|
||||
export let value
|
||||
$: truncatedValue = truncate(value, { length: 12 })
|
||||
</script>
|
||||
|
||||
{truncatedValue}
|
|
@ -1,13 +1,29 @@
|
|||
<script>
|
||||
import { BackupTrigger } from "constants/backend/backups"
|
||||
export let row
|
||||
|
||||
$: baseTrig = row?.trigger || "manual"
|
||||
$: trigger = row?.trigger || "manual"
|
||||
$: type = row?.type || "backup"
|
||||
$: trigger = baseTrig.charAt(0).toUpperCase() + baseTrig.slice(1)
|
||||
|
||||
function printTrigger(trig) {
|
||||
let final = "undefined"
|
||||
switch (trig) {
|
||||
case BackupTrigger.PUBLISH:
|
||||
final = "published"
|
||||
break
|
||||
case BackupTrigger.RESTORING:
|
||||
final = "pre-restore"
|
||||
break
|
||||
default:
|
||||
final = trig
|
||||
break
|
||||
}
|
||||
return final.charAt(0).toUpperCase() + final.slice(1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="cell">
|
||||
{trigger}
|
||||
{printTrigger(trigger)}
|
||||
{type}
|
||||
</div>
|
||||
|
||||
|
|
11
packages/builder/src/constants/backend/backups.js
Normal file
11
packages/builder/src/constants/backend/backups.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
export const BackupTrigger = {
|
||||
MANUAL: "manual",
|
||||
PUBLISH: "publish",
|
||||
RESTORING: "restoring",
|
||||
SCHEDULED: "scheduled",
|
||||
}
|
||||
|
||||
export const BackupType = {
|
||||
BACKUP: "backup",
|
||||
RESTORE: "restore",
|
||||
}
|
|
@ -383,10 +383,5 @@
|
|||
.user-dropdown {
|
||||
flex: 0 1 0;
|
||||
}
|
||||
|
||||
/* Reduce BBUI page padding */
|
||||
.content :global(> *) {
|
||||
padding: calc(var(--spacing-xl) * 1.5) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -5,9 +5,16 @@
|
|||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let filter = null
|
||||
$: filteredGroups = !filter
|
||||
? $groups
|
||||
: $groups.filter(group =>
|
||||
group.name?.toLowerCase().includes(filter.toLowerCase())
|
||||
)
|
||||
|
||||
$: optionSections = {
|
||||
groups: {
|
||||
data: $groups,
|
||||
data: filteredGroups,
|
||||
getLabel: group => group.name,
|
||||
getValue: group => group._id,
|
||||
getIcon: group => group.icon,
|
||||
|
@ -15,21 +22,28 @@
|
|||
},
|
||||
}
|
||||
|
||||
$: appData = [{ id: "", role: "" }]
|
||||
|
||||
$: onChange = selected => {
|
||||
const { detail } = selected
|
||||
if (!detail) return
|
||||
if (!detail || Object.keys(detail).length == 0) {
|
||||
dispatch("change", null)
|
||||
return
|
||||
}
|
||||
|
||||
const groupSelected = $groups.find(x => x._id === detail)
|
||||
const appIds = groupSelected?.apps || null
|
||||
dispatch("change", appIds)
|
||||
const appRoleIds = groupSelected?.roles
|
||||
? Object.keys(groupSelected?.roles)
|
||||
: []
|
||||
dispatch("change", appRoleIds)
|
||||
}
|
||||
</script>
|
||||
|
||||
<PickerDropdown
|
||||
autocomplete
|
||||
bind:searchTerm={filter}
|
||||
primaryOptions={optionSections}
|
||||
placeholder={"Filter by access"}
|
||||
on:pickprimary={onChange}
|
||||
on:closed={() => {
|
||||
filter = null
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -20,7 +20,14 @@
|
|||
import { store, automationStore } from "builderStore"
|
||||
import { API } from "api"
|
||||
import { onMount } from "svelte"
|
||||
import { apps, auth, admin, templates, licensing } from "stores/portal"
|
||||
import {
|
||||
apps,
|
||||
auth,
|
||||
admin,
|
||||
templates,
|
||||
licensing,
|
||||
groups,
|
||||
} from "stores/portal"
|
||||
import { goto } from "@roxi/routify"
|
||||
import AppRow from "components/start/AppRow.svelte"
|
||||
import { AppStatus } from "constants"
|
||||
|
@ -59,10 +66,15 @@
|
|||
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
||||
$: filteredApps = enrichedApps.filter(
|
||||
app =>
|
||||
app?.name?.toLowerCase().includes(searchTerm.toLowerCase()) &&
|
||||
(accessFilterList !== null ? accessFilterList.includes(app?.appId) : true)
|
||||
(searchTerm
|
||||
? app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
: true) &&
|
||||
(accessFilterList !== null
|
||||
? accessFilterList?.includes(
|
||||
`${app?.type}_${app?.tenantId}_${app?.appId}`
|
||||
)
|
||||
: true)
|
||||
)
|
||||
|
||||
$: lockedApps = filteredApps.filter(app => app?.lockedYou || app?.lockedOther)
|
||||
$: unlocked = lockedApps?.length === 0
|
||||
$: automationErrors = getAutomationErrors(enrichedApps)
|
||||
|
@ -231,6 +243,10 @@
|
|||
// always load latest
|
||||
await licensing.init()
|
||||
|
||||
if ($licensing.groupsEnabled) {
|
||||
await groups.actions.init()
|
||||
}
|
||||
|
||||
if ($templates?.length === 0) {
|
||||
notifications.error(
|
||||
"There was a problem loading quick start templates."
|
||||
|
|
|
@ -391,11 +391,7 @@
|
|||
gap: var(--spacing-l);
|
||||
}
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.overview-wrap :global(.content > *) {
|
||||
padding: calc(var(--spacing-xl) * 1.5) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.app-title {
|
||||
display: flex;
|
||||
gap: var(--spacing-m);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
@ -26,9 +26,9 @@
|
|||
"outputPath": "build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.0.40-alpha.4",
|
||||
"@budibase/string-templates": "2.0.40-alpha.4",
|
||||
"@budibase/types": "2.0.40-alpha.4",
|
||||
"@budibase/backend-core": "^2.1.11",
|
||||
"@budibase/string-templates": "^2.1.11",
|
||||
"@budibase/types": "^2.1.11",
|
||||
"axios": "0.21.2",
|
||||
"chalk": "4.1.0",
|
||||
"cli-progress": "3.11.2",
|
||||
|
|
|
@ -5037,45 +5037,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"name": "Grid (Beta)",
|
||||
"icon": "ViewGrid",
|
||||
"hasChildren": true,
|
||||
"styles": [
|
||||
"size"
|
||||
],
|
||||
"illegalChildren": ["section", "grid"],
|
||||
"legalDirectChildren": [
|
||||
"container",
|
||||
"tableblock",
|
||||
"cardsblock",
|
||||
"repeaterblock",
|
||||
"formblock"
|
||||
],
|
||||
"size": {
|
||||
"width": 800,
|
||||
"height": 400
|
||||
},
|
||||
"showEmptyState": false,
|
||||
"settings": [
|
||||
{
|
||||
"type": "number",
|
||||
"label": "Rows",
|
||||
"key": "rows",
|
||||
"defaultValue": 12,
|
||||
"min": 1,
|
||||
"max": 32
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"label": "Columns",
|
||||
"key": "cols",
|
||||
"defaultValue": 12,
|
||||
"min": 1,
|
||||
"max": 32
|
||||
}
|
||||
]
|
||||
},
|
||||
"formblock": {
|
||||
"name": "Form Block",
|
||||
"icon": "Form",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"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": "2.0.40-alpha.4",
|
||||
"@budibase/frontend-core": "2.0.40-alpha.4",
|
||||
"@budibase/string-templates": "2.0.40-alpha.4",
|
||||
"@budibase/bbui": "^2.1.11",
|
||||
"@budibase/frontend-core": "^2.1.11",
|
||||
"@budibase/string-templates": "^2.1.11",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
|
|
@ -85,13 +85,8 @@
|
|||
valueType: "Binding",
|
||||
},
|
||||
]
|
||||
// If we're using an "update" form, use the real data provider. If we're
|
||||
// using a create form, we just want a fake array so that our repeater
|
||||
// will actually render the form, but data doesn't matter.
|
||||
$: dataProvider =
|
||||
actionType !== "Create"
|
||||
? `{{ literal ${safe(providerId)} }}`
|
||||
: { rows: [{}] }
|
||||
|
||||
$: dataProvider = `{{ literal ${safe(providerId)} }}`
|
||||
$: renderDeleteButton = showDeleteButton && actionType === "Update"
|
||||
$: renderSaveButton = showSaveButton && actionType !== "View"
|
||||
$: renderButtons = renderDeleteButton || renderSaveButton
|
||||
|
|
|
@ -128,6 +128,23 @@
|
|||
return fields.find(field => get(field).name === name)
|
||||
}
|
||||
|
||||
const getDefault = (defaultValue, schema, type) => {
|
||||
// Remove any values not present in the field schema
|
||||
// Convert any values supplied to string
|
||||
if (Array.isArray(defaultValue) && type == "array") {
|
||||
return defaultValue.reduce((acc, entry) => {
|
||||
let processedOption = String(entry)
|
||||
let schemaOptions = schema.constraints.inclusion
|
||||
if (schemaOptions.indexOf(processedOption) > -1) {
|
||||
acc.push(processedOption)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
} else {
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
const formApi = {
|
||||
registerField: (
|
||||
field,
|
||||
|
@ -153,8 +170,10 @@
|
|||
table
|
||||
)
|
||||
|
||||
const parsedDefault = getDefault(defaultValue, schema?.[field], type)
|
||||
|
||||
// If we've already registered this field then keep some existing state
|
||||
let initialValue = Helpers.deepGet(initialValues, field) ?? defaultValue
|
||||
let initialValue = Helpers.deepGet(initialValues, field) ?? parsedDefault
|
||||
let initialError = null
|
||||
let fieldId = `id-${Helpers.uuid()}`
|
||||
const existingField = getField(field)
|
||||
|
@ -187,11 +206,11 @@
|
|||
error: initialError,
|
||||
disabled:
|
||||
disabled || fieldDisabled || (isAutoColumn && !editAutoColumns),
|
||||
defaultValue,
|
||||
defaultValue: parsedDefault,
|
||||
validator,
|
||||
lastUpdate: Date.now(),
|
||||
},
|
||||
fieldApi: makeFieldApi(field, defaultValue),
|
||||
fieldApi: makeFieldApi(field, parsedDefault),
|
||||
fieldSchema: schema?.[field] ?? {},
|
||||
})
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@budibase/frontend-core",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Budibase frontend core libraries used in builder and client",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.0.40-alpha.4",
|
||||
"@budibase/bbui": "^2.1.11",
|
||||
"lodash": "^4.17.21",
|
||||
"svelte": "^3.46.2"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/sdk",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Budibase Public API SDK",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -77,11 +77,11 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "2.0.40-alpha.4",
|
||||
"@budibase/client": "2.0.40-alpha.4",
|
||||
"@budibase/pro": "2.0.40-alpha.4",
|
||||
"@budibase/string-templates": "2.0.40-alpha.4",
|
||||
"@budibase/types": "2.0.40-alpha.4",
|
||||
"@budibase/backend-core": "^2.1.11",
|
||||
"@budibase/client": "^2.1.11",
|
||||
"@budibase/pro": "2.1.11",
|
||||
"@budibase/string-templates": "^2.1.11",
|
||||
"@budibase/types": "^2.1.11",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
|
@ -82,10 +82,20 @@ exports.validate = async ({ tableId, row, table }) => {
|
|||
// non required MultiSelect creates an empty array, which should not throw errors
|
||||
errors[fieldName] = [`${fieldName} is required`]
|
||||
}
|
||||
} else if (type === FieldTypes.JSON && typeof row[fieldName] === "string") {
|
||||
} else if (
|
||||
(type === FieldTypes.ATTACHMENT || type === FieldTypes.JSON) &&
|
||||
typeof row[fieldName] === "string"
|
||||
) {
|
||||
// this should only happen if there is an error
|
||||
try {
|
||||
JSON.parse(row[fieldName])
|
||||
const json = JSON.parse(row[fieldName])
|
||||
if (type === FieldTypes.ATTACHMENT) {
|
||||
if (Array.isArray(json)) {
|
||||
row[fieldName] = json
|
||||
} else {
|
||||
errors[fieldName] = [`Must be an array`]
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
errors[fieldName] = [`Contains invalid JSON`]
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ require("svelte/register")
|
|||
const send = require("koa-send")
|
||||
const { resolve, join } = require("../../../utilities/centralPath")
|
||||
const uuid = require("uuid")
|
||||
const { ObjectStoreBuckets, ATTACHMENT_DIR } = require("../../../constants")
|
||||
const { ObjectStoreBuckets } = require("../../../constants")
|
||||
const { processString } = require("@budibase/string-templates")
|
||||
const {
|
||||
loadHandlebarsFile,
|
||||
|
@ -90,7 +90,7 @@ export const uploadFile = async function (ctx: any) {
|
|||
|
||||
return prepareUpload({
|
||||
file,
|
||||
s3Key: `${ctx.appId}/${ATTACHMENT_DIR}/${processedFileName}`,
|
||||
s3Key: `${ctx.appId}/attachments/${processedFileName}`,
|
||||
bucket: ObjectStoreBuckets.APPS,
|
||||
})
|
||||
})
|
||||
|
|
|
@ -221,6 +221,7 @@ export interface components {
|
|||
*/
|
||||
type?:
|
||||
| "string"
|
||||
| "barcodeqr"
|
||||
| "longform"
|
||||
| "options"
|
||||
| "number"
|
||||
|
@ -326,6 +327,7 @@ export interface components {
|
|||
*/
|
||||
type?:
|
||||
| "string"
|
||||
| "barcodeqr"
|
||||
| "longform"
|
||||
| "options"
|
||||
| "number"
|
||||
|
@ -433,6 +435,7 @@ export interface components {
|
|||
*/
|
||||
type?:
|
||||
| "string"
|
||||
| "barcodeqr"
|
||||
| "longform"
|
||||
| "options"
|
||||
| "number"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/types",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Budibase types",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.0.40-alpha.4",
|
||||
"version": "2.1.11",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -36,10 +36,10 @@
|
|||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.0.40-alpha.4",
|
||||
"@budibase/pro": "2.0.40-alpha.4",
|
||||
"@budibase/string-templates": "2.0.40-alpha.4",
|
||||
"@budibase/types": "2.0.40-alpha.4",
|
||||
"@budibase/backend-core": "^2.1.11",
|
||||
"@budibase/pro": "2.1.11",
|
||||
"@budibase/string-templates": "^2.1.11",
|
||||
"@budibase/types": "^2.1.11",
|
||||
"@koa/router": "8.0.8",
|
||||
"@sentry/node": "6.17.7",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
|
|
|
@ -86,7 +86,6 @@ describe("Internal API - /applications endpoints", () => {
|
|||
|
||||
// unpublish app
|
||||
await config.applications.unpublish(<string>app.appId)
|
||||
|
||||
})
|
||||
|
||||
it("POST - Sync application before deployment", async () => {
|
||||
|
|
Loading…
Reference in a new issue