Merge branch 'develop' of github.com:Budibase/budibase into lab-day-state
This commit is contained in:
commit
81ade833dd
|
@ -119,6 +119,8 @@ services:
|
||||||
|
|
||||||
watchtower-service:
|
watchtower-service:
|
||||||
image: containrrr/watchtower
|
image: containrrr/watchtower
|
||||||
|
ports:
|
||||||
|
- "${WATCHTOWER_PORT}:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
command: --debug --http-api-update bbapps bbworker
|
command: --debug --http-api-update bbapps bbworker
|
||||||
|
@ -128,8 +130,6 @@ services:
|
||||||
- WATCHTOWER_CLEANUP=true
|
- WATCHTOWER_CLEANUP=true
|
||||||
labels:
|
labels:
|
||||||
- "com.centurylinklabs.watchtower.enable=false"
|
- "com.centurylinklabs.watchtower.enable=false"
|
||||||
ports:
|
|
||||||
- 6161:8080
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -17,4 +17,5 @@ WORKER_PORT=4003
|
||||||
MINIO_PORT=4004
|
MINIO_PORT=4004
|
||||||
COUCH_DB_PORT=4005
|
COUCH_DB_PORT=4005
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
WATCHTOWER_PORT=6161
|
||||||
BUDIBASE_ENVIRONMENT=PRODUCTION
|
BUDIBASE_ENVIRONMENT=PRODUCTION
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/auth",
|
"name": "@budibase/auth",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"description": "Authentication middlewares for budibase builder and apps",
|
"description": "Authentication middlewares for budibase builder and apps",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/bbui",
|
"name": "@budibase/bbui",
|
||||||
"description": "A UI solution used in the different Budibase projects.",
|
"description": "A UI solution used in the different Budibase projects.",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"svelte": "src/index.js",
|
"svelte": "src/index.js",
|
||||||
"module": "dist/bbui.es.js",
|
"module": "dist/bbui.es.js",
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/label/dist/index-vars.css"
|
||||||
|
import Badge from "../Badge/Badge.svelte"
|
||||||
|
export let value
|
||||||
|
|
||||||
|
const displayLimit = 5
|
||||||
|
|
||||||
|
$: badges = value?.slice(0, displayLimit) ?? []
|
||||||
|
$: leftover = (value?.length ?? 0) - badges.length
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each badges as badge}
|
||||||
|
<Badge size="S" grey>{badge}</Badge>
|
||||||
|
{/each}
|
||||||
|
{#if leftover}
|
||||||
|
<div>+{leftover} more</div>
|
||||||
|
{/if}
|
|
@ -4,7 +4,7 @@
|
||||||
import DateTimeRenderer from "./DateTimeRenderer.svelte"
|
import DateTimeRenderer from "./DateTimeRenderer.svelte"
|
||||||
import RelationshipRenderer from "./RelationshipRenderer.svelte"
|
import RelationshipRenderer from "./RelationshipRenderer.svelte"
|
||||||
import AttachmentRenderer from "./AttachmentRenderer.svelte"
|
import AttachmentRenderer from "./AttachmentRenderer.svelte"
|
||||||
|
import ArrayRenderer from "./ArrayRenderer.svelte"
|
||||||
export let row
|
export let row
|
||||||
export let schema
|
export let schema
|
||||||
export let value
|
export let value
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
options: StringRenderer,
|
options: StringRenderer,
|
||||||
number: StringRenderer,
|
number: StringRenderer,
|
||||||
longform: StringRenderer,
|
longform: StringRenderer,
|
||||||
|
array: ArrayRenderer,
|
||||||
}
|
}
|
||||||
$: type = schema?.type ?? "string"
|
$: type = schema?.type ?? "string"
|
||||||
$: customRenderer = customRenderers?.find(x => x.column === schema?.name)
|
$: customRenderer = customRenderers?.find(x => x.column === schema?.name)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -65,10 +65,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^0.9.105-alpha.32",
|
"@budibase/bbui": "^0.9.116-alpha.3",
|
||||||
"@budibase/client": "^0.9.105-alpha.32",
|
"@budibase/client": "^0.9.116-alpha.3",
|
||||||
"@budibase/colorpicker": "1.1.2",
|
"@budibase/colorpicker": "1.1.2",
|
||||||
"@budibase/string-templates": "^0.9.105-alpha.32",
|
"@budibase/string-templates": "^0.9.116-alpha.3",
|
||||||
"@sentry/browser": "5.19.1",
|
"@sentry/browser": "5.19.1",
|
||||||
"@spectrum-css/page": "^3.0.1",
|
"@spectrum-css/page": "^3.0.1",
|
||||||
"@spectrum-css/vars": "^3.0.1",
|
"@spectrum-css/vars": "^3.0.1",
|
||||||
|
|
|
@ -23,6 +23,7 @@ async function activate() {
|
||||||
if (posthogConfigured) {
|
if (posthogConfigured) {
|
||||||
posthog.init(process.env.POSTHOG_TOKEN, {
|
posthog.init(process.env.POSTHOG_TOKEN, {
|
||||||
autocapture: false,
|
autocapture: false,
|
||||||
|
capture_pageview: false,
|
||||||
api_host: process.env.POSTHOG_URL,
|
api_host: process.env.POSTHOG_URL,
|
||||||
})
|
})
|
||||||
posthog.set_config({ persistence: "cookie" })
|
posthog.set_config({ persistence: "cookie" })
|
||||||
|
@ -79,6 +80,7 @@ const isFeedbackTimeElapsed = sinceDateStr => {
|
||||||
const feedbackMilliseconds = feedbackHours * 60 * 60 * 1000
|
const feedbackMilliseconds = feedbackHours * 60 * 60 * 1000
|
||||||
return Date.now() > sinceDate + feedbackMilliseconds
|
return Date.now() > sinceDate + feedbackMilliseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitFeedback(values) {
|
function submitFeedback(values) {
|
||||||
if (!analyticsEnabled || !process.env.POSTHOG_TOKEN) return
|
if (!analyticsEnabled || !process.env.POSTHOG_TOKEN) return
|
||||||
localStorage.setItem(FEEDBACK_SUBMITTED_KEY, Date.now())
|
localStorage.setItem(FEEDBACK_SUBMITTED_KEY, Date.now())
|
||||||
|
|
|
@ -43,6 +43,7 @@ const createScreen = table => {
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
type: "table",
|
type: "table",
|
||||||
},
|
},
|
||||||
|
size: "spectrum--medium",
|
||||||
})
|
})
|
||||||
|
|
||||||
const fieldGroup = new Component("@budibase/standard-components/fieldgroup")
|
const fieldGroup = new Component("@budibase/standard-components/fieldgroup")
|
||||||
|
|
|
@ -101,7 +101,6 @@ const createScreen = table => {
|
||||||
.instanceName("Form")
|
.instanceName("Form")
|
||||||
.customProps({
|
.customProps({
|
||||||
actionType: "Update",
|
actionType: "Update",
|
||||||
theme: "spectrum--lightest",
|
|
||||||
size: "spectrum--medium",
|
size: "spectrum--medium",
|
||||||
dataSource: {
|
dataSource: {
|
||||||
label: table.name,
|
label: table.name,
|
||||||
|
|
|
@ -65,6 +65,7 @@ const createScreen = table => {
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
type: "table",
|
type: "table",
|
||||||
},
|
},
|
||||||
|
size: "spectrum--medium",
|
||||||
paginate: true,
|
paginate: true,
|
||||||
limit: 8,
|
limit: 8,
|
||||||
})
|
})
|
||||||
|
|
|
@ -131,6 +131,7 @@ const fieldTypeToComponentMap = {
|
||||||
string: "stringfield",
|
string: "stringfield",
|
||||||
number: "numberfield",
|
number: "numberfield",
|
||||||
options: "optionsfield",
|
options: "optionsfield",
|
||||||
|
array: "multifieldselect",
|
||||||
boolean: "booleanfield",
|
boolean: "booleanfield",
|
||||||
longform: "longformfield",
|
longform: "longformfield",
|
||||||
datetime: "datetimefield",
|
datetime: "datetimefield",
|
||||||
|
@ -167,6 +168,13 @@ export function makeDatasourceFormComponents(datasource) {
|
||||||
optionsSource: "schema",
|
optionsSource: "schema",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (fieldType === "array") {
|
||||||
|
component.customProps({
|
||||||
|
placeholder: "Choose an option",
|
||||||
|
optionsSource: "schema",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (fieldType === "link") {
|
if (fieldType === "link") {
|
||||||
let placeholder =
|
let placeholder =
|
||||||
fieldSchema.relationshipType === "one-to-many"
|
fieldSchema.relationshipType === "one-to-many"
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { Input, Select, DatePicker, Toggle, TextArea } from "@budibase/bbui"
|
import {
|
||||||
|
Input,
|
||||||
|
Select,
|
||||||
|
DatePicker,
|
||||||
|
Toggle,
|
||||||
|
TextArea,
|
||||||
|
Multiselect,
|
||||||
|
} from "@budibase/bbui"
|
||||||
import Dropzone from "components/common/Dropzone.svelte"
|
import Dropzone from "components/common/Dropzone.svelte"
|
||||||
import { capitalise } from "helpers"
|
import { capitalise } from "helpers"
|
||||||
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
|
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
|
||||||
|
@ -27,6 +34,8 @@
|
||||||
<Dropzone {label} bind:value />
|
<Dropzone {label} bind:value />
|
||||||
{:else if type === "boolean"}
|
{:else if type === "boolean"}
|
||||||
<Toggle text={label} bind:value data-cy="{meta.name}-input" />
|
<Toggle text={label} bind:value data-cy="{meta.name}-input" />
|
||||||
|
{:else if type === "array"}
|
||||||
|
<Multiselect bind:value {label} options={meta.constraints.inclusion} />
|
||||||
{:else if type === "link"}
|
{:else if type === "link"}
|
||||||
<LinkedRowSelector bind:linkedRows={value} schema={meta} />
|
<LinkedRowSelector bind:linkedRows={value} schema={meta} />
|
||||||
{:else if type === "longform"}
|
{:else if type === "longform"}
|
||||||
|
|
|
@ -262,6 +262,11 @@
|
||||||
label="Options (one per line)"
|
label="Options (one per line)"
|
||||||
bind:values={field.constraints.inclusion}
|
bind:values={field.constraints.inclusion}
|
||||||
/>
|
/>
|
||||||
|
{:else if field.type === "array"}
|
||||||
|
<ValuesList
|
||||||
|
label="Options (one per line)"
|
||||||
|
bind:values={field.constraints.inclusion}
|
||||||
|
/>
|
||||||
{:else if field.type === "datetime"}
|
{:else if field.type === "datetime"}
|
||||||
<DatePicker
|
<DatePicker
|
||||||
label="Earliest"
|
label="Earliest"
|
||||||
|
|
|
@ -113,6 +113,10 @@
|
||||||
label: "Options",
|
label: "Options",
|
||||||
value: FIELDS.OPTIONS.type,
|
value: FIELDS.OPTIONS.type,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Multi-select",
|
||||||
|
value: FIELDS.ARRAY.type,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
"datetimefield",
|
"datetimefield",
|
||||||
"attachmentfield",
|
"attachmentfield",
|
||||||
"relationshipfield",
|
"relationshipfield",
|
||||||
"daterangepicker"
|
"daterangepicker",
|
||||||
|
"multifieldselect"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, allScreens, selectedAccessRole } from "builderStore"
|
import { store, allScreens, selectedAccessRole } from "builderStore"
|
||||||
import { tables, roles } from "stores/backend"
|
import { tables } from "stores/backend"
|
||||||
|
import { roles } from "stores/backend"
|
||||||
import { Input, Select, ModalContent, Toggle } from "@budibase/bbui"
|
import { Input, Select, ModalContent, Toggle } from "@budibase/bbui"
|
||||||
import getTemplates from "builderStore/store/screenTemplates"
|
import getTemplates from "builderStore/store/screenTemplates"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
let createLink = true
|
let createLink = true
|
||||||
let roleId = $selectedAccessRole || "BASIC"
|
let roleId = $selectedAccessRole || "BASIC"
|
||||||
|
|
||||||
$: templates = getTemplates($store, tables.getDataSources())
|
$: templates = getTemplates($store, $tables.list)
|
||||||
$: route = !route && $allScreens.length === 0 ? "*" : route
|
$: route = !route && $allScreens.length === 0 ? "*" : route
|
||||||
$: {
|
$: {
|
||||||
if (templates && templateIndex === undefined) {
|
if (templates && templateIndex === undefined) {
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
export let bindings = []
|
export let bindings = []
|
||||||
|
|
||||||
$: text = value?.label ?? "Choose an option"
|
$: text = value?.label ?? "Choose an option"
|
||||||
$: tables = tablesStore.getDataSources().map(m => ({
|
$: tables = $tablesStore.list.map(m => ({
|
||||||
label: m.name,
|
label: m.name,
|
||||||
tableId: m._id,
|
tableId: m._id,
|
||||||
type: "table",
|
type: "table",
|
||||||
|
|
|
@ -59,6 +59,14 @@
|
||||||
expression.operator = validOperators[0] ?? OperatorOptions.Equals.value
|
expression.operator = validOperators[0] ?? OperatorOptions.Equals.value
|
||||||
onOperatorChange(expression, expression.operator)
|
onOperatorChange(expression, expression.operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if changed to an array, change default value to empty array
|
||||||
|
const idx = filters.findIndex(x => x.field === field)
|
||||||
|
if (expression.type === "array") {
|
||||||
|
filters[idx].value = []
|
||||||
|
} else {
|
||||||
|
filters[idx].value = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onOperatorChange = (expression, operator) => {
|
const onOperatorChange = (expression, operator) => {
|
||||||
|
@ -74,7 +82,9 @@
|
||||||
|
|
||||||
const getFieldOptions = field => {
|
const getFieldOptions = field => {
|
||||||
const schema = schemaFields.find(x => x.name === field)
|
const schema = schemaFields.find(x => x.name === field)
|
||||||
return schema?.constraints?.inclusion || []
|
const opt = schema?.constraints?.inclusion || []
|
||||||
|
|
||||||
|
return opt
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -122,7 +132,7 @@
|
||||||
/>
|
/>
|
||||||
{:else if ["string", "longform", "number"].includes(filter.type)}
|
{:else if ["string", "longform", "number"].includes(filter.type)}
|
||||||
<Input disabled={filter.noValue} bind:value={filter.value} />
|
<Input disabled={filter.noValue} bind:value={filter.value} />
|
||||||
{:else if filter.type === "options"}
|
{:else if filter.type === "options" || "array"}
|
||||||
<Combobox
|
<Combobox
|
||||||
disabled={filter.noValue}
|
disabled={filter.noValue}
|
||||||
options={getFieldOptions(filter.field)}
|
options={getFieldOptions(filter.field)}
|
||||||
|
|
|
@ -58,11 +58,11 @@
|
||||||
value: "notRegex",
|
value: "notRegex",
|
||||||
},
|
},
|
||||||
Contains: {
|
Contains: {
|
||||||
label: "Must contain row ID",
|
label: "Must contain",
|
||||||
value: "contains",
|
value: "contains",
|
||||||
},
|
},
|
||||||
NotContains: {
|
NotContains: {
|
||||||
label: "Must not contain row ID",
|
label: "Must not contain",
|
||||||
value: "notContains",
|
value: "notContains",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,13 @@
|
||||||
Constraints.MinLength,
|
Constraints.MinLength,
|
||||||
Constraints.MaxLength,
|
Constraints.MaxLength,
|
||||||
],
|
],
|
||||||
|
["array"]: [
|
||||||
|
Constraints.Required,
|
||||||
|
Constraints.MinLength,
|
||||||
|
Constraints.MaxLength,
|
||||||
|
Constraints.Contains,
|
||||||
|
Constraints.NotContains,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
$: dataSourceSchema = getDataSourceSchema($currentAsset, $selectedComponent)
|
$: dataSourceSchema = getDataSourceSchema($currentAsset, $selectedComponent)
|
||||||
|
@ -109,7 +116,6 @@
|
||||||
$: schemaRules = parseRulesFromSchema(field, dataSourceSchema || {})
|
$: schemaRules = parseRulesFromSchema(field, dataSourceSchema || {})
|
||||||
$: fieldType = type?.split("/")[1] || "string"
|
$: fieldType = type?.split("/")[1] || "string"
|
||||||
$: constraintOptions = getConstraintsForType(fieldType)
|
$: constraintOptions = getConstraintsForType(fieldType)
|
||||||
|
|
||||||
const getConstraintsForType = type => {
|
const getConstraintsForType = type => {
|
||||||
return ConstraintMap[type]
|
return ConstraintMap[type]
|
||||||
}
|
}
|
||||||
|
@ -190,6 +196,7 @@
|
||||||
valueType: "Binding",
|
valueType: "Binding",
|
||||||
type: fieldType,
|
type: fieldType,
|
||||||
id: generate(),
|
id: generate(),
|
||||||
|
value: fieldType == "array" ? [] : null,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -275,7 +282,7 @@
|
||||||
disabled={rule.constraint === "required"}
|
disabled={rule.constraint === "required"}
|
||||||
on:change={e => (rule.value = e.detail)}
|
on:change={e => (rule.value = e.detail)}
|
||||||
/>
|
/>
|
||||||
{:else if ["maxLength", "minLength", "regex", "notRegex", "contains", "notContains"].includes(rule.constraint)}
|
{:else if rule.type !== "array" && ["maxLength", "minLength", "regex", "notRegex", "contains", "notContains"].includes(rule.constraint)}
|
||||||
<!-- Certain constraints always need string values-->
|
<!-- Certain constraints always need string values-->
|
||||||
<Input
|
<Input
|
||||||
bind:value={rule.value}
|
bind:value={rule.value}
|
||||||
|
@ -289,6 +296,15 @@
|
||||||
bind:value={rule.value}
|
bind:value={rule.value}
|
||||||
placeholder="Constraint value"
|
placeholder="Constraint value"
|
||||||
/>
|
/>
|
||||||
|
{:else if rule.type === "array"}
|
||||||
|
<Select
|
||||||
|
disabled={rule.constraint === "required"}
|
||||||
|
options={dataSourceSchema.schema[field].constraints
|
||||||
|
.inclusion}
|
||||||
|
getOptionLabel={x => x}
|
||||||
|
getOptionValue={x => x}
|
||||||
|
value={rule.value}
|
||||||
|
/>
|
||||||
{:else if rule.type === "boolean"}
|
{:else if rule.type === "boolean"}
|
||||||
<Select
|
<Select
|
||||||
disabled={rule.constraint === "required"}
|
disabled={rule.constraint === "required"}
|
||||||
|
|
|
@ -43,9 +43,11 @@ const componentMap = {
|
||||||
"field/datetime": FormFieldSelect,
|
"field/datetime": FormFieldSelect,
|
||||||
"field/attachment": FormFieldSelect,
|
"field/attachment": FormFieldSelect,
|
||||||
"field/link": FormFieldSelect,
|
"field/link": FormFieldSelect,
|
||||||
|
"field/array": FormFieldSelect,
|
||||||
// Some validation types are the same as others, so not all types are
|
// Some validation types are the same as others, so not all types are
|
||||||
// explicitly listed here. e.g. options uses string validation
|
// explicitly listed here. e.g. options uses string validation
|
||||||
"validation/string": ValidationEditor,
|
"validation/string": ValidationEditor,
|
||||||
|
"validation/array": ValidationEditor,
|
||||||
"validation/number": ValidationEditor,
|
"validation/number": ValidationEditor,
|
||||||
"validation/boolean": ValidationEditor,
|
"validation/boolean": ValidationEditor,
|
||||||
"validation/datetime": ValidationEditor,
|
"validation/datetime": ValidationEditor,
|
||||||
|
|
|
@ -235,6 +235,7 @@
|
||||||
|
|
||||||
.viewer {
|
.viewer {
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
|
width: 640px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview {
|
.preview {
|
||||||
|
|
|
@ -26,6 +26,15 @@ export const FIELDS = {
|
||||||
inclusion: [],
|
inclusion: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ARRAY: {
|
||||||
|
name: "Multi-select",
|
||||||
|
type: "array",
|
||||||
|
constraints: {
|
||||||
|
type: "array",
|
||||||
|
presence: false,
|
||||||
|
inclusion: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
NUMBER: {
|
NUMBER: {
|
||||||
name: "Number",
|
name: "Number",
|
||||||
type: "number",
|
type: "number",
|
||||||
|
|
|
@ -31,6 +31,14 @@ export const OperatorOptions = {
|
||||||
value: "rangeHigh",
|
value: "rangeHigh",
|
||||||
label: "Less than",
|
label: "Less than",
|
||||||
},
|
},
|
||||||
|
Contains: {
|
||||||
|
value: "equal",
|
||||||
|
label: "Contains",
|
||||||
|
},
|
||||||
|
NotContains: {
|
||||||
|
value: "notEqual",
|
||||||
|
label: "Does Not Contain",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getValidOperatorsForType = type => {
|
export const getValidOperatorsForType = type => {
|
||||||
|
@ -55,6 +63,8 @@ export const getValidOperatorsForType = type => {
|
||||||
]
|
]
|
||||||
} else if (type === "options") {
|
} else if (type === "options") {
|
||||||
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
|
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
|
||||||
|
} else if (type === "array") {
|
||||||
|
return [Op.Contains, Op.NotContains, Op.Empty, Op.NotEmpty]
|
||||||
} else if (type === "boolean") {
|
} else if (type === "boolean") {
|
||||||
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
|
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
|
||||||
} else if (type === "longform") {
|
} else if (type === "longform") {
|
||||||
|
|
|
@ -87,7 +87,6 @@ export function createTablesStore() {
|
||||||
draft: {},
|
draft: {},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getDataSources: () => get(store).list.filter(t => t.name !== "Users"),
|
|
||||||
delete: async table => {
|
delete: async table => {
|
||||||
await api.delete(`/api/tables/${table._id}/${table._rev}`)
|
await api.delete(`/api/tables/${table._id}/${table._rev}`)
|
||||||
update(state => ({
|
update(state => ({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/cli",
|
"name": "@budibase/cli",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
@ -15,5 +15,6 @@ exports.AnalyticsEvents = {
|
||||||
SelfHostInit: "hosting_init",
|
SelfHostInit: "hosting_init",
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.BUDIBASE_POSTHOG_URL = "https://posthog.budi.live"
|
exports.BUDIBASE_POSTHOG_URL = "https://app.posthog.com"
|
||||||
exports.BUDIBASE_POSTHOG_TOKEN = "Oeq9KzIpZYaNsXIvHw5QTZWNpfiG_EOjAOpjTyAiitY"
|
exports.BUDIBASE_POSTHOG_TOKEN =
|
||||||
|
"phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS"
|
||||||
|
|
|
@ -26,6 +26,7 @@ WORKER_PORT=4003
|
||||||
MINIO_PORT=4004
|
MINIO_PORT=4004
|
||||||
COUCH_DB_PORT=4005
|
COUCH_DB_PORT=4005
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
WATCHTOWER_PORT=6161
|
||||||
BUDIBASE_ENVIRONMENT=PRODUCTION`
|
BUDIBASE_ENVIRONMENT=PRODUCTION`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/client",
|
"name": "@budibase/client",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"module": "dist/budibase-client.js",
|
"module": "dist/budibase-client.js",
|
||||||
"main": "dist/budibase-client.js",
|
"main": "dist/budibase-client.js",
|
||||||
|
@ -18,9 +18,9 @@
|
||||||
"dev:builder": "rollup -cw"
|
"dev:builder": "rollup -cw"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^0.9.105-alpha.32",
|
"@budibase/bbui": "^0.9.116-alpha.3",
|
||||||
"@budibase/standard-components": "^0.9.105-alpha.32",
|
"@budibase/standard-components": "^0.9.116-alpha.3",
|
||||||
"@budibase/string-templates": "^0.9.105-alpha.32",
|
"@budibase/string-templates": "^0.9.116-alpha.3",
|
||||||
"regexparam": "^1.3.0",
|
"regexparam": "^1.3.0",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
"svelte-spa-router": "^3.0.5"
|
"svelte-spa-router": "^3.0.5"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"description": "Budibase Web Server",
|
"description": "Budibase Web Server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -62,9 +62,9 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/auth": "^0.9.105-alpha.32",
|
"@budibase/auth": "^0.9.116-alpha.3",
|
||||||
"@budibase/client": "^0.9.105-alpha.32",
|
"@budibase/client": "^0.9.116-alpha.3",
|
||||||
"@budibase/string-templates": "^0.9.105-alpha.32",
|
"@budibase/string-templates": "^0.9.116-alpha.3",
|
||||||
"@elastic/elasticsearch": "7.10.0",
|
"@elastic/elasticsearch": "7.10.0",
|
||||||
"@koa/router": "8.0.0",
|
"@koa/router": "8.0.0",
|
||||||
"@sendgrid/mail": "7.1.1",
|
"@sendgrid/mail": "7.1.1",
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.3",
|
"@babel/core": "^7.14.3",
|
||||||
"@babel/preset-env": "^7.14.4",
|
"@babel/preset-env": "^7.14.4",
|
||||||
"@budibase/standard-components": "^0.9.105-alpha.32",
|
"@budibase/standard-components": "^0.9.116-alpha.3",
|
||||||
"@jest/test-sequencer": "^24.8.0",
|
"@jest/test-sequencer": "^24.8.0",
|
||||||
"@types/bull": "^3.15.1",
|
"@types/bull": "^3.15.1",
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
|
|
|
@ -60,8 +60,8 @@ exports.buildSchemaFromDb = async function (ctx) {
|
||||||
exports.update = async function (ctx) {
|
exports.update = async function (ctx) {
|
||||||
const db = new CouchDB(ctx.appId)
|
const db = new CouchDB(ctx.appId)
|
||||||
const datasourceId = ctx.params.datasourceId
|
const datasourceId = ctx.params.datasourceId
|
||||||
const datasource = await db.get(datasourceId)
|
let datasource = await db.get(datasourceId)
|
||||||
datasource.name = ctx.request.body.name
|
datasource = { ...datasource, ...ctx.request.body }
|
||||||
|
|
||||||
const response = await db.put(datasource)
|
const response = await db.put(datasource)
|
||||||
datasource._rev = response.rev
|
datasource._rev = response.rev
|
||||||
|
|
|
@ -211,7 +211,6 @@ class QueryBuilder {
|
||||||
if (this.query.notEmpty) {
|
if (this.query.notEmpty) {
|
||||||
build(this.query.notEmpty, key => `${key}:["" TO *]`)
|
build(this.query.notEmpty, key => `${key}:["" TO *]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +252,7 @@ const runQuery = async (url, body) => {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
})
|
})
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
|
|
||||||
let output = {
|
let output = {
|
||||||
rows: [],
|
rows: [],
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,12 +58,24 @@ exports.validate = async ({ appId, tableId, row, table }) => {
|
||||||
const constraints = cloneDeep(table.schema[fieldName].constraints)
|
const constraints = cloneDeep(table.schema[fieldName].constraints)
|
||||||
// special case for options, need to always allow unselected (null)
|
// special case for options, need to always allow unselected (null)
|
||||||
if (
|
if (
|
||||||
table.schema[fieldName].type === FieldTypes.OPTIONS &&
|
table.schema[fieldName].type ===
|
||||||
|
(FieldTypes.OPTIONS || FieldTypes.ARRAY) &&
|
||||||
constraints.inclusion
|
constraints.inclusion
|
||||||
) {
|
) {
|
||||||
constraints.inclusion.push(null)
|
constraints.inclusion.push(null)
|
||||||
}
|
}
|
||||||
const res = validateJs.single(row[fieldName], constraints)
|
let res
|
||||||
|
|
||||||
|
// Validate.js doesn't seem to handle array
|
||||||
|
if (table.schema[fieldName].type === FieldTypes.ARRAY) {
|
||||||
|
row[fieldName].map(val => {
|
||||||
|
if (!constraints.inclusion.includes(val)) {
|
||||||
|
errors[fieldName] = "Field not in list"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res = validateJs.single(row[fieldName], constraints)
|
||||||
|
}
|
||||||
if (res) errors[fieldName] = res
|
if (res) errors[fieldName] = res
|
||||||
}
|
}
|
||||||
return { valid: Object.keys(errors).length === 0, errors }
|
return { valid: Object.keys(errors).length === 0, errors }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const CouchDB = require("../../../db")
|
const CouchDB = require("../../../db")
|
||||||
|
const linkRows = require("../../../db/linkedRows")
|
||||||
const csvParser = require("../../../utilities/csvParser")
|
const csvParser = require("../../../utilities/csvParser")
|
||||||
const {
|
const {
|
||||||
getRowParams,
|
getRowParams,
|
||||||
|
@ -74,6 +75,16 @@ exports.handleDataImport = async (appId, user, table, dataImport) => {
|
||||||
const processed = inputProcessing(user, table, row)
|
const processed = inputProcessing(user, table, row)
|
||||||
table = processed.table
|
table = processed.table
|
||||||
row = processed.row
|
row = processed.row
|
||||||
|
|
||||||
|
// make sure link rows are up to date
|
||||||
|
row = await linkRows.updateLinks({
|
||||||
|
appId,
|
||||||
|
eventType: linkRows.EventType.ROW_SAVE,
|
||||||
|
row,
|
||||||
|
tableId: row.tableId,
|
||||||
|
table,
|
||||||
|
})
|
||||||
|
|
||||||
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
||||||
// check whether the options need to be updated for inclusion as part of the data import
|
// check whether the options need to be updated for inclusion as part of the data import
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -94,7 +94,7 @@ describe("/datasources", () => {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
// this is mock data, can't test it
|
// this is mock data, can't test it
|
||||||
expect(res.body).toBeDefined()
|
expect(res.body).toBeDefined()
|
||||||
expect(pg.queryMock).toHaveBeenCalledWith(`select "users"."name" as "users.name", "users"."age" as "users.age" from "users" where "users"."name" like $1 limit $2`, ["John%", 5000])
|
expect(pg.queryMock).toHaveBeenCalledWith(`select "users"."name" as "users.name", "users"."age" as "users.age" from "users" where "users"."name" ilike $1 limit $2`, ["John%", 5000])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ exports.FieldTypes = {
|
||||||
OPTIONS: "options",
|
OPTIONS: "options",
|
||||||
NUMBER: "number",
|
NUMBER: "number",
|
||||||
BOOLEAN: "boolean",
|
BOOLEAN: "boolean",
|
||||||
|
ARRAY: "array",
|
||||||
DATETIME: "datetime",
|
DATETIME: "datetime",
|
||||||
ATTACHMENT: "attachment",
|
ATTACHMENT: "attachment",
|
||||||
LINK: "link",
|
LINK: "link",
|
||||||
|
|
|
@ -99,7 +99,14 @@ exports.createAllSearchIndex = async appId => {
|
||||||
for (let key of Object.keys(input)) {
|
for (let key of Object.keys(input)) {
|
||||||
let idxKey = prev != null ? `${prev}.${key}` : key
|
let idxKey = prev != null ? `${prev}.${key}` : key
|
||||||
idxKey = idxKey.replace(/ /, "_")
|
idxKey = idxKey.replace(/ /, "_")
|
||||||
if (key === "_id" || key === "_rev" || input[key] == null) {
|
if (Array.isArray(input[key])) {
|
||||||
|
for (let val in input[key]) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
index(idxKey, input[key][val], {
|
||||||
|
store: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (key === "_id" || key === "_rev" || input[key] == null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (typeof input[key] === "string") {
|
if (typeof input[key] === "string") {
|
||||||
|
|
|
@ -52,7 +52,7 @@ function addFilters(
|
||||||
if (filters.string) {
|
if (filters.string) {
|
||||||
iterate(filters.string, (key, value) => {
|
iterate(filters.string, (key, value) => {
|
||||||
const fnc = allOr ? "orWhere" : "where"
|
const fnc = allOr ? "orWhere" : "where"
|
||||||
query = query[fnc](key, "like", `${value}%`)
|
query = query[fnc](key, "ilike", `${value}%`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (filters.range) {
|
if (filters.range) {
|
||||||
|
|
|
@ -82,7 +82,7 @@ describe("SQL query builder", () => {
|
||||||
}))
|
}))
|
||||||
expect(query).toEqual({
|
expect(query).toEqual({
|
||||||
bindings: ["John%", limit],
|
bindings: ["John%", limit],
|
||||||
sql: `select * from "${TABLE_NAME}" where "${TABLE_NAME}"."name" like $1 limit $2`
|
sql: `select * from "${TABLE_NAME}" where "${TABLE_NAME}"."name" ilike $1 limit $2`
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,11 @@ const TYPE_TRANSFORM_MAP = {
|
||||||
[null]: null,
|
[null]: null,
|
||||||
[undefined]: undefined,
|
[undefined]: undefined,
|
||||||
},
|
},
|
||||||
|
[FieldTypes.ARRAY]: {
|
||||||
|
"": [],
|
||||||
|
[null]: [],
|
||||||
|
[undefined]: undefined,
|
||||||
|
},
|
||||||
[FieldTypes.STRING]: {
|
[FieldTypes.STRING]: {
|
||||||
"": "",
|
"": "",
|
||||||
[null]: "",
|
[null]: "",
|
||||||
|
|
|
@ -1726,6 +1726,21 @@
|
||||||
"label": "Custom"
|
"label": "Custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "Size",
|
||||||
|
"key": "size",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"label": "Medium",
|
||||||
|
"value": "spectrum--medium"
|
||||||
|
}, {
|
||||||
|
"label": "Large",
|
||||||
|
"value": "spectrum--large"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"defaultValue": "spectrum--medium"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"label": "Disabled",
|
"label": "Disabled",
|
||||||
|
@ -2041,6 +2056,108 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"multifieldselect": {
|
||||||
|
"name": "Multi-select Picker",
|
||||||
|
"icon": "ViewList",
|
||||||
|
"styles": ["size"],
|
||||||
|
"illegalChildren": ["section"],
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "field/array",
|
||||||
|
"label": "Field",
|
||||||
|
"key": "field"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Label",
|
||||||
|
"key": "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Placeholder",
|
||||||
|
"key": "placeholder",
|
||||||
|
"placeholder": "Choose an option"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Default value",
|
||||||
|
"key": "defaultValue"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Autocomplete",
|
||||||
|
"key": "autocomplete",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Disabled",
|
||||||
|
"key": "disabled",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "Options source",
|
||||||
|
"key": "optionsSource",
|
||||||
|
"defaultValue": "schema",
|
||||||
|
"placeholder": "Pick an options source",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"label": "Schema",
|
||||||
|
"value": "schema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Data provider",
|
||||||
|
"value": "provider"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Custom",
|
||||||
|
"value": "custom"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "dataProvider",
|
||||||
|
"label": "Options Provider",
|
||||||
|
"key": "dataProvider",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "optionsSource",
|
||||||
|
"value": "provider"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"label": "Label Column",
|
||||||
|
"key": "labelColumn",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "optionsSource",
|
||||||
|
"value": "provider"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"label": "Value Column",
|
||||||
|
"key": "valueColumn",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "optionsSource",
|
||||||
|
"value": "provider"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "options",
|
||||||
|
"key": "customOptions",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "optionsSource",
|
||||||
|
"value": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "validation/array",
|
||||||
|
"label": "Validation",
|
||||||
|
"key": "validation"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"booleanfield": {
|
"booleanfield": {
|
||||||
"name": "Checkbox",
|
"name": "Checkbox",
|
||||||
"icon": "Checkmark",
|
"icon": "Checkmark",
|
||||||
|
@ -2346,6 +2463,22 @@
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
"placeholder": "All columns"
|
"placeholder": "All columns"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "Size",
|
||||||
|
"key": "size",
|
||||||
|
"defaultValue": "spectrum--medium",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"label": "Medium",
|
||||||
|
"value": "spectrum--medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Large",
|
||||||
|
"value": "spectrum--large"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"label": "Quiet",
|
"label": "Quiet",
|
||||||
|
|
|
@ -29,11 +29,11 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"svelte"
|
"svelte"
|
||||||
],
|
],
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
|
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^0.9.105-alpha.32",
|
"@budibase/bbui": "^0.9.116-alpha.3",
|
||||||
"@spectrum-css/button": "^3.0.3",
|
"@spectrum-css/button": "^3.0.3",
|
||||||
"@spectrum-css/card": "^3.0.3",
|
"@spectrum-css/card": "^3.0.3",
|
||||||
"@spectrum-css/divider": "^1.0.3",
|
"@spectrum-css/divider": "^1.0.3",
|
||||||
|
|
|
@ -29,12 +29,9 @@
|
||||||
if (["user", "url"].includes(context.closestComponentId)) {
|
if (["user", "url"].includes(context.closestComponentId)) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
// Only inherit values if the table ID matches
|
// Always inherit the closest data source
|
||||||
const closestContext = context[`${context.closestComponentId}`] || {}
|
const closestContext = context[`${context.closestComponentId}`] || {}
|
||||||
if (dataSource.tableId !== closestContext?.tableId) {
|
return closestContext || {}
|
||||||
return {}
|
|
||||||
}
|
|
||||||
return closestContext
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetches the form schema from this form's dataSource, if one exists
|
// Fetches the form schema from this form's dataSource, if one exists
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
export let dataSource
|
export let dataSource
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let initialValues
|
export let initialValues
|
||||||
|
export let size
|
||||||
export let schema
|
export let schema
|
||||||
export let table
|
export let table
|
||||||
|
|
||||||
|
@ -270,7 +271,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Provider {actions} data={dataContext}>
|
<Provider {actions} data={dataContext}>
|
||||||
<div use:styleable={$component.styles}>
|
<div use:styleable={$component.styles} class={size}>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<script>
|
||||||
|
import { CoreMultiselect } from "@budibase/bbui"
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import { getOptions } from "./optionsParser"
|
||||||
|
export let field
|
||||||
|
export let label
|
||||||
|
export let placeholder
|
||||||
|
export let disabled = false
|
||||||
|
export let validation
|
||||||
|
export let defaultValue
|
||||||
|
export let optionsSource = "schema"
|
||||||
|
export let dataProvider
|
||||||
|
export let labelColumn
|
||||||
|
export let valueColumn
|
||||||
|
export let customOptions
|
||||||
|
export let autocomplete = false
|
||||||
|
|
||||||
|
let fieldState
|
||||||
|
let fieldApi
|
||||||
|
let fieldSchema
|
||||||
|
|
||||||
|
$: flatOptions = optionsSource == null || optionsSource === "schema"
|
||||||
|
$: options = getOptions(
|
||||||
|
optionsSource,
|
||||||
|
fieldSchema,
|
||||||
|
dataProvider,
|
||||||
|
labelColumn,
|
||||||
|
valueColumn,
|
||||||
|
customOptions
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Field
|
||||||
|
{field}
|
||||||
|
{label}
|
||||||
|
{disabled}
|
||||||
|
{validation}
|
||||||
|
{defaultValue}
|
||||||
|
type="array"
|
||||||
|
bind:fieldState
|
||||||
|
bind:fieldApi
|
||||||
|
bind:fieldSchema
|
||||||
|
>
|
||||||
|
{#if fieldState}
|
||||||
|
<CoreMultiselect
|
||||||
|
value={fieldState.value || []}
|
||||||
|
error={fieldState.error}
|
||||||
|
getOptionLabel={flatOptions ? x => x : x => x.label}
|
||||||
|
getOptionValue={flatOptions ? x => x : x => x.value}
|
||||||
|
id={fieldState.fieldId}
|
||||||
|
disabled={fieldState.disabled}
|
||||||
|
on:change={e => fieldApi.setValue(e.detail)}
|
||||||
|
{placeholder}
|
||||||
|
{options}
|
||||||
|
{autocomplete}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</Field>
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { CoreSelect, CoreRadioGroup } from "@budibase/bbui"
|
import { CoreSelect, CoreRadioGroup } from "@budibase/bbui"
|
||||||
import Field from "./Field.svelte"
|
import Field from "./Field.svelte"
|
||||||
|
import { getOptions } from "./optionsParser"
|
||||||
export let field
|
export let field
|
||||||
export let label
|
export let label
|
||||||
export let placeholder
|
export let placeholder
|
||||||
|
@ -26,41 +26,9 @@
|
||||||
fieldSchema,
|
fieldSchema,
|
||||||
dataProvider,
|
dataProvider,
|
||||||
labelColumn,
|
labelColumn,
|
||||||
valueColumn
|
valueColumn,
|
||||||
|
customOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
const getOptions = (
|
|
||||||
optionsSource,
|
|
||||||
fieldSchema,
|
|
||||||
dataProvider,
|
|
||||||
labelColumn,
|
|
||||||
valueColumn
|
|
||||||
) => {
|
|
||||||
// Take options from schema
|
|
||||||
if (optionsSource == null || optionsSource === "schema") {
|
|
||||||
return fieldSchema?.constraints?.inclusion ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract options from data provider
|
|
||||||
if (optionsSource === "provider" && valueColumn) {
|
|
||||||
let optionsSet = {}
|
|
||||||
dataProvider?.rows?.forEach(row => {
|
|
||||||
const value = row?.[valueColumn]
|
|
||||||
if (value) {
|
|
||||||
const label = row[labelColumn] || value
|
|
||||||
optionsSet[value] = { value, label }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return Object.values(optionsSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract custom options
|
|
||||||
if (optionsSource === "custom" && customOptions) {
|
|
||||||
return customOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Field
|
<Field
|
||||||
|
|
|
@ -3,6 +3,7 @@ export { default as fieldgroup } from "./FieldGroup.svelte"
|
||||||
export { default as stringfield } from "./StringField.svelte"
|
export { default as stringfield } from "./StringField.svelte"
|
||||||
export { default as numberfield } from "./NumberField.svelte"
|
export { default as numberfield } from "./NumberField.svelte"
|
||||||
export { default as optionsfield } from "./OptionsField.svelte"
|
export { default as optionsfield } from "./OptionsField.svelte"
|
||||||
|
export { default as multifieldselect } from "./MultiFieldSelect.svelte"
|
||||||
export { default as booleanfield } from "./BooleanField.svelte"
|
export { default as booleanfield } from "./BooleanField.svelte"
|
||||||
export { default as longformfield } from "./LongFormField.svelte"
|
export { default as longformfield } from "./LongFormField.svelte"
|
||||||
export { default as datetimefield } from "./DateTimeField.svelte"
|
export { default as datetimefield } from "./DateTimeField.svelte"
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
export const getOptions = (
|
||||||
|
optionsSource,
|
||||||
|
fieldSchema,
|
||||||
|
dataProvider,
|
||||||
|
labelColumn,
|
||||||
|
valueColumn,
|
||||||
|
customOptions
|
||||||
|
) => {
|
||||||
|
const isArray = fieldSchema?.type === "array"
|
||||||
|
// Take options from schema
|
||||||
|
if (optionsSource == null || optionsSource === "schema") {
|
||||||
|
return fieldSchema?.constraints?.inclusion ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionsSource === "provider" && isArray) {
|
||||||
|
let optionsSet = {}
|
||||||
|
|
||||||
|
dataProvider?.rows?.forEach(row => {
|
||||||
|
const value = row?.[valueColumn]
|
||||||
|
if (value) {
|
||||||
|
const label = row[labelColumn] || value
|
||||||
|
optionsSet[value] = { value, label }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return Object.values(optionsSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract options from data provider
|
||||||
|
if (optionsSource === "provider" && valueColumn) {
|
||||||
|
let optionsSet = {}
|
||||||
|
dataProvider?.rows?.forEach(row => {
|
||||||
|
const value = row?.[valueColumn]
|
||||||
|
if (value) {
|
||||||
|
const label = row[labelColumn] || value
|
||||||
|
optionsSet[value] = { value, label }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return Object.values(optionsSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract custom options
|
||||||
|
if (optionsSource === "custom" && customOptions) {
|
||||||
|
return customOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ export const createValidatorFromConstraints = (
|
||||||
schemaConstraints.presence?.allowEmpty === false
|
schemaConstraints.presence?.allowEmpty === false
|
||||||
) {
|
) {
|
||||||
rules.push({
|
rules.push({
|
||||||
type: "string",
|
type: schemaConstraints.type == "array" ? "array" : "string",
|
||||||
constraint: "required",
|
constraint: "required",
|
||||||
error: "Required",
|
error: "Required",
|
||||||
})
|
})
|
||||||
|
@ -63,7 +63,10 @@ export const createValidatorFromConstraints = (
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inclusion constraint
|
// Inclusion constraint
|
||||||
if (exists(schemaConstraints.inclusion)) {
|
if (
|
||||||
|
exists(schemaConstraints.inclusion) &&
|
||||||
|
schemaConstraints.type !== "array"
|
||||||
|
) {
|
||||||
const options = schemaConstraints.inclusion || []
|
const options = schemaConstraints.inclusion || []
|
||||||
rules.push({
|
rules.push({
|
||||||
type: "string",
|
type: "string",
|
||||||
|
@ -142,7 +145,7 @@ const evaluateRule = (rule, value) => {
|
||||||
* in the same format.
|
* in the same format.
|
||||||
* @param value the value to parse
|
* @param value the value to parse
|
||||||
* @param type the type to parse
|
* @param type the type to parse
|
||||||
* @returns {boolean|string|*|number|null} the parsed value, or null if invalid
|
* @returns {boolean|string|*|number|null|array} the parsed value, or null if invalid
|
||||||
*/
|
*/
|
||||||
const parseType = (value, type) => {
|
const parseType = (value, type) => {
|
||||||
// Treat nulls or empty strings as null
|
// Treat nulls or empty strings as null
|
||||||
|
@ -202,6 +205,13 @@ const parseType = (value, type) => {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === "array") {
|
||||||
|
if (!Array.isArray(value) || !value.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
// If some unknown type, treat as null to avoid breaking validators
|
// If some unknown type, treat as null to avoid breaking validators
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ export const buildLuceneQuery = filter => {
|
||||||
notEqual: {},
|
notEqual: {},
|
||||||
empty: {},
|
empty: {},
|
||||||
notEmpty: {},
|
notEmpty: {},
|
||||||
|
contains: {},
|
||||||
|
notContains: {},
|
||||||
}
|
}
|
||||||
if (Array.isArray(filter)) {
|
if (Array.isArray(filter)) {
|
||||||
filter.forEach(expression => {
|
filter.forEach(expression => {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
export let showAutoColumns
|
export let showAutoColumns
|
||||||
export let rowCount
|
export let rowCount
|
||||||
export let quiet
|
export let quiet
|
||||||
|
export let size
|
||||||
|
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
const { styleable } = getContext("sdk")
|
const { styleable } = getContext("sdk")
|
||||||
|
@ -71,7 +72,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:styleable={$component.styles}>
|
<div use:styleable={$component.styles} class={size}>
|
||||||
<Table
|
<Table
|
||||||
{data}
|
{data}
|
||||||
{schema}
|
{schema}
|
||||||
|
|
|
@ -2,6 +2,59 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@adobe/spectrum-css-workflow-icons@^1.2.1":
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4"
|
||||||
|
integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w==
|
||||||
|
|
||||||
|
"@budibase/bbui@^0.9.115":
|
||||||
|
version "0.9.115"
|
||||||
|
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.115.tgz#6aa0226908812052cd02628d6d604b95a3d55b92"
|
||||||
|
integrity sha512-HysxPp8POetLWj1pucrhn4Na+KllKvHRmBV7qU9XE1BVL9B2pLa6rPoZeLYrdMQmBW070bmXSdUuYDWZqEYYog==
|
||||||
|
dependencies:
|
||||||
|
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
|
||||||
|
"@spectrum-css/actionbutton" "^1.0.1"
|
||||||
|
"@spectrum-css/actiongroup" "^1.0.1"
|
||||||
|
"@spectrum-css/avatar" "^3.0.2"
|
||||||
|
"@spectrum-css/button" "^3.0.1"
|
||||||
|
"@spectrum-css/buttongroup" "^3.0.2"
|
||||||
|
"@spectrum-css/checkbox" "^3.0.2"
|
||||||
|
"@spectrum-css/dialog" "^3.0.1"
|
||||||
|
"@spectrum-css/divider" "^1.0.1"
|
||||||
|
"@spectrum-css/dropzone" "^3.0.2"
|
||||||
|
"@spectrum-css/fieldgroup" "^3.0.2"
|
||||||
|
"@spectrum-css/fieldlabel" "^3.0.1"
|
||||||
|
"@spectrum-css/icon" "^3.0.1"
|
||||||
|
"@spectrum-css/illustratedmessage" "^3.0.2"
|
||||||
|
"@spectrum-css/inputgroup" "^3.0.2"
|
||||||
|
"@spectrum-css/label" "^2.0.10"
|
||||||
|
"@spectrum-css/link" "^3.1.1"
|
||||||
|
"@spectrum-css/menu" "^3.0.1"
|
||||||
|
"@spectrum-css/modal" "^3.0.1"
|
||||||
|
"@spectrum-css/pagination" "^3.0.3"
|
||||||
|
"@spectrum-css/picker" "^1.0.1"
|
||||||
|
"@spectrum-css/popover" "^3.0.1"
|
||||||
|
"@spectrum-css/progressbar" "^1.0.2"
|
||||||
|
"@spectrum-css/progresscircle" "^1.0.2"
|
||||||
|
"@spectrum-css/radio" "^3.0.2"
|
||||||
|
"@spectrum-css/search" "^3.0.2"
|
||||||
|
"@spectrum-css/sidenav" "^3.0.2"
|
||||||
|
"@spectrum-css/statuslight" "^3.0.2"
|
||||||
|
"@spectrum-css/switch" "^1.0.2"
|
||||||
|
"@spectrum-css/table" "^3.0.1"
|
||||||
|
"@spectrum-css/tabs" "^3.0.1"
|
||||||
|
"@spectrum-css/tags" "^3.0.2"
|
||||||
|
"@spectrum-css/textfield" "^3.0.1"
|
||||||
|
"@spectrum-css/toast" "^3.0.1"
|
||||||
|
"@spectrum-css/tooltip" "^3.0.3"
|
||||||
|
"@spectrum-css/treeview" "^3.0.2"
|
||||||
|
"@spectrum-css/typography" "^3.0.1"
|
||||||
|
"@spectrum-css/underlay" "^2.0.9"
|
||||||
|
"@spectrum-css/vars" "^3.0.1"
|
||||||
|
dayjs "^1.10.4"
|
||||||
|
svelte-flatpickr "^3.1.0"
|
||||||
|
svelte-portal "^1.0.0"
|
||||||
|
|
||||||
"@rollup/pluginutils@^4.1.1":
|
"@rollup/pluginutils@^4.1.1":
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec"
|
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec"
|
||||||
|
@ -10,28 +63,103 @@
|
||||||
estree-walker "^2.0.1"
|
estree-walker "^2.0.1"
|
||||||
picomatch "^2.2.2"
|
picomatch "^2.2.2"
|
||||||
|
|
||||||
"@spectrum-css/button@^3.0.3":
|
"@spectrum-css/actionbutton@^1.0.1":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.3.tgz#8f7342a69b303c5acdcfa0a59f5e9267b9f3cb30"
|
||||||
|
integrity sha512-P9qoCPSiZ1SB6ZYqK5hub0vGty00YYqonQE0KTjtb1i+T1nYR/87vWqVPERx9j63uhgZncjwFYaThTvRqye7eQ==
|
||||||
|
|
||||||
|
"@spectrum-css/actiongroup@^1.0.1":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.3.tgz#4713ce65e6f5c72c404a7b638fbc3b4fd7e3874f"
|
||||||
|
integrity sha512-NlB9Q4ZlWixXxymoPIYG6g2hkwAGKFodHWPFfxHD8ddkjXWRB9G2akUP7cfsJ4DcYn4VisUORCOYQwqDiSmboQ==
|
||||||
|
|
||||||
|
"@spectrum-css/avatar@^3.0.2":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/avatar/-/avatar-3.0.2.tgz#4f1826223eae330e64b6d3cc899e9bc2e98dac95"
|
||||||
|
integrity sha512-wEczvSqxttTWSiL3cOvXV/RmGRwSkw2w6+slcHhnf0kb7ovymMM+9oz8vvEpEsSeo5u598bc+7ktrKFpAd6soQ==
|
||||||
|
|
||||||
|
"@spectrum-css/button@^3.0.1", "@spectrum-css/button@^3.0.3":
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84"
|
||||||
integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg==
|
integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg==
|
||||||
|
|
||||||
|
"@spectrum-css/buttongroup@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.3.tgz#719d868845ac9d2c4f939c1b9f6044507902d5aa"
|
||||||
|
integrity sha512-eXl8U4QWMWXqyTu654FdQdEGnmczgOYlpIFSHyCMVjhtPqZp2xwnLFiGh6LKw+bLio6eeOZ0L+vpk1GcoYqgkw==
|
||||||
|
|
||||||
"@spectrum-css/card@^3.0.3":
|
"@spectrum-css/card@^3.0.3":
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b"
|
||||||
integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg==
|
integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg==
|
||||||
|
|
||||||
"@spectrum-css/divider@^1.0.3":
|
"@spectrum-css/checkbox@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.3.tgz#8577067fc8b97e4609f92bd242364937a533a7bb"
|
||||||
|
integrity sha512-QVG9uMHq+lh70Dh6mDNnY+vEvNz2p7VC6xgLfDYfijp2qeiqYPq72fQK6p/SiyqPk96ZACzNRwgeROU6Xf6Wgg==
|
||||||
|
|
||||||
|
"@spectrum-css/dialog@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.3.tgz#7715a4ea435e753afb623d99ca5917ed1bcd6f34"
|
||||||
|
integrity sha512-AhmKgfRIVyTe3ABiJ8lLUQL34VB/H6fN16na2LlbDRJvyRMzkdN1Xf2i6U3f4OMd3qQ8Gm5xat4BvMxIQPBAUQ==
|
||||||
|
|
||||||
|
"@spectrum-css/divider@^1.0.1", "@spectrum-css/divider@^1.0.3":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.3.tgz#639e2ebaa0834efa40f42397668bbd5c153ea385"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.3.tgz#639e2ebaa0834efa40f42397668bbd5c153ea385"
|
||||||
integrity sha512-Zy4Rn40w8UtzMh3wx/U9+CepSCpm1aOCGftHgWDub0XZuVTzh0c1WwyzTuLCx2Hf21z5VRGNiDh8bGEEzSbtNA==
|
integrity sha512-Zy4Rn40w8UtzMh3wx/U9+CepSCpm1aOCGftHgWDub0XZuVTzh0c1WwyzTuLCx2Hf21z5VRGNiDh8bGEEzSbtNA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@spectrum-css/vars" "^3.0.2"
|
"@spectrum-css/vars" "^3.0.2"
|
||||||
|
|
||||||
"@spectrum-css/link@^3.1.3":
|
"@spectrum-css/dropzone@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.3.tgz#aee71697a2c195947599d7541b858c3c198741dc"
|
||||||
|
integrity sha512-ujrswdtB6bHigklyHsm6zomFd6rUnKJ3xVVRjroVF4+ouK4DxK5tX0iVd0EW6AOfOjx4Cc28uyFot3fpxp+MQw==
|
||||||
|
|
||||||
|
"@spectrum-css/fieldgroup@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.0.3.tgz#85d85da048d08200f25ceab378026dd2b11e0bb2"
|
||||||
|
integrity sha512-wXUXTXN1CPnR7M4Ltd+3uh7BfcNGUV1+Xe0/h0tCpq/j+S2Sd4xo7/pUMdU19sIDrAAtpEFp1tt+nouHcU5HGQ==
|
||||||
|
|
||||||
|
"@spectrum-css/fieldlabel@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449"
|
||||||
|
integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ==
|
||||||
|
|
||||||
|
"@spectrum-css/icon@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.3.tgz#5c612822380927087aebd526855d82ed2c3e2cba"
|
||||||
|
integrity sha512-hyloKOejPCXhP3MBNsm3SjR9j8xT1R1S19p32KW/0Qhj+VMUtfyEPmevyFptpn7wcovQccdl/vZVIVDuML/imw==
|
||||||
|
|
||||||
|
"@spectrum-css/illustratedmessage@^3.0.2":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.2.tgz#6a480be98b027e050b086e7899e40d87adb0a8c0"
|
||||||
|
integrity sha512-dqnE8X27bGcO0HN8+dYx8O4o0dNNIAqeivOzDHhe2El+V4dTzMrNIerF6G0NLm3GjVf6XliwmitsZK+K6FmbtA==
|
||||||
|
|
||||||
|
"@spectrum-css/inputgroup@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.3.tgz#00c9a370ddc2c55cf0f37dd6069faa9501fd7eb5"
|
||||||
|
integrity sha512-FqRJTiLL7jiGfzDVXWUGVLqHryJjCcqQIrqAi+Tq0oenapzsBe2qc/zIrKgh2wtMI+NTIBLXTECvij3L1HlqAg==
|
||||||
|
|
||||||
|
"@spectrum-css/label@^2.0.10":
|
||||||
|
version "2.0.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001"
|
||||||
|
integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ==
|
||||||
|
|
||||||
|
"@spectrum-css/link@^3.1.1", "@spectrum-css/link@^3.1.3":
|
||||||
version "3.1.3"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.3.tgz#b0e560a7e0acdb4a2b329b6669696aa3438f5993"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.3.tgz#b0e560a7e0acdb4a2b329b6669696aa3438f5993"
|
||||||
integrity sha512-8Pmy5d73MwKcATTPaj+fSrZYnIw7GmfX40AvpC1xx5LauOxsbUb4AVNp1kn2H8rrOBmxF7czyhoBBhEiv66QUg==
|
integrity sha512-8Pmy5d73MwKcATTPaj+fSrZYnIw7GmfX40AvpC1xx5LauOxsbUb4AVNp1kn2H8rrOBmxF7czyhoBBhEiv66QUg==
|
||||||
|
|
||||||
|
"@spectrum-css/menu@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.3.tgz#46a9b221bb5f470a2f8a934bdfd512d84d2fdc4d"
|
||||||
|
integrity sha512-qKA9J/MrikNKIpCEHsAazG2vY3im5tjGCmo6p9Pdnu8/aQMsiuZDHZayukeCttJUZkrb9guDVL9OIHlK5RZvcQ==
|
||||||
|
|
||||||
|
"@spectrum-css/modal@^3.0.1":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.2.tgz#58b6621cab65f90788d310374f40df1f7090473f"
|
||||||
|
integrity sha512-YnIivJhoaao7Otu+HV7sgebPyFbO6sd/oMvTN/Rb2wwgnaMnIIuIRdGandSrcgotN2uNgs+P0knG6mv/xA1/dg==
|
||||||
|
|
||||||
"@spectrum-css/page@^3.0.1":
|
"@spectrum-css/page@^3.0.1":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/page/-/page-3.0.2.tgz#8f0c03d25f5565fb13115541a8fcaf0e1d3a8ee0"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/page/-/page-3.0.2.tgz#8f0c03d25f5565fb13115541a8fcaf0e1d3a8ee0"
|
||||||
|
@ -39,11 +167,101 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@spectrum-css/vars" "^3.0.2"
|
"@spectrum-css/vars" "^3.0.2"
|
||||||
|
|
||||||
"@spectrum-css/typography@^3.0.2":
|
"@spectrum-css/pagination@^3.0.3":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.3.tgz#b204c3ada384c4af751a354bc428346d82eeea65"
|
||||||
|
integrity sha512-OJ/v9GeNXJOZ9Yr9LDBYPrR2NCiLOWP9wANT/a5sqFuugRnQbn/HYMnRp9TBxwpDY6ihaPo0T/wi7kLiAJFdDw==
|
||||||
|
|
||||||
|
"@spectrum-css/picker@^1.0.1":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.0.3.tgz#21379bcf8ae94277deeb6ad65dcd9e2bbfacb487"
|
||||||
|
integrity sha512-oHLGxBx5BwVCSGo7/T1C9PTHX1+/5AmVjyLiTJ4UoIdSJmOERw9YcRZbcGZgBJNWbxcjr4TyGtwj1EcSjEy97w==
|
||||||
|
|
||||||
|
"@spectrum-css/popover@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.3.tgz#6fb69873474fb968afb738eacb9e121f93e83a09"
|
||||||
|
integrity sha512-KvmXv4TV19FBx39KfmgVlDYtvtBqv/8RRK7RRLDDHGViTxZtShjVsVpwIgfkfgn4iJztCnXpWzFqRXWUu2XCpQ==
|
||||||
|
|
||||||
|
"@spectrum-css/progressbar@^1.0.2":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.3.tgz#f70bcc38a2a21cff2f422ec825724ebbb9455e67"
|
||||||
|
integrity sha512-vJHplefUuy8+NjCw1X7fLbqHVGNVBpvGFXNAeaIj4SFf4ygxiUq/5c9iRhhsCQixEsJlfD/b7BnGXU7BUDkr6Q==
|
||||||
|
|
||||||
|
"@spectrum-css/progresscircle@^1.0.2":
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.2.tgz#258ea9170fb70f795edda03e38a61d93bef4487c"
|
||||||
|
integrity sha512-JLULpyzjIY95lzlWR1yE1gv4l1K6p+scQ+edmuZZUHBzwM3pUtkvHJmUlA9TYdResUYW6Uka60VRdY6lZ8gnFQ==
|
||||||
|
|
||||||
|
"@spectrum-css/radio@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.3.tgz#25c3bc5e9c30a8a8ae728717b7c7fb736cdae640"
|
||||||
|
integrity sha512-LaLGfz/eGNR2iyqouXYILIA+pKRqF769iPdwM0REm5RpWvMQDD7rPZ/kWlg18owjaFsyllEp25gEjmhRJIIVOw==
|
||||||
|
|
||||||
|
"@spectrum-css/search@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.0.3.tgz#3415dc106aca0d5dd996e87084a1b47c2b95a882"
|
||||||
|
integrity sha512-kdLpKTt0obljuhS1q1tukujRlvSs8sBwij76D4Qp8KpMzwePfZyvv1kYzuWPNZfTeISxWsmyZ6Wxd1uvzjn+UA==
|
||||||
|
|
||||||
|
"@spectrum-css/sidenav@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.3.tgz#132141fbd2500a927c312fa4e1d712c438b3d597"
|
||||||
|
integrity sha512-cQ+CgwjxGftrcc79i1XnGd66QTl7H7zopSU0UTV4Qq7hvqfrjjWxfZ6b+3tezrrhNlDope1ff9o8sm67PsPXtg==
|
||||||
|
|
||||||
|
"@spectrum-css/statuslight@^3.0.2":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.2.tgz#dc54b6cd113413dcdb909c486b5d7bae60db65c5"
|
||||||
|
integrity sha512-xodB8g8vGJH20XmUj9ZsPlM1jHrGeRbvmVXkz0q7YvQrYAhim8pP3W+XKKZAletPFAuu8cmUOc6SWn6i4X4z6w==
|
||||||
|
|
||||||
|
"@spectrum-css/switch@^1.0.2":
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.2.tgz#f0b4c69271964573e02b08e90998096e49e1de44"
|
||||||
|
integrity sha512-zqmHpgWPNg1gEwdUNFYV3CBX5JaeALfIqcJIxE0FLZqr9d1C4+oLE0ItIFzt1bwr4bFAOmkEpvtiY+amluzGxQ==
|
||||||
|
|
||||||
|
"@spectrum-css/table@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.3.tgz#7f7f19905ef3275cbf907ce3a5818e63c30b2caf"
|
||||||
|
integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg==
|
||||||
|
|
||||||
|
"@spectrum-css/tabs@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.0.3.tgz#51dd6f168c897b0fdc3a7e9f901df7bd2288b4fc"
|
||||||
|
integrity sha512-iLP1I72bJWz9APdQB1jiw+pOv5a7N+hYOCJvRoc56Us/hJKVzowkyGRe3uH+8v36nCG9bHxiAQNLoU8eXisVrg==
|
||||||
|
|
||||||
|
"@spectrum-css/tags@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.3.tgz#fc76d2735cdc442de91b7eb3bee49a928c0767ac"
|
||||||
|
integrity sha512-SL8vPxVDfWcY5VdIuyl0TImEXcOU1I7yCyXkk7MudMwfnYs81FaIyY32hFV9OHj0Tz/36UzRzc7AVMSuRQ53pw==
|
||||||
|
|
||||||
|
"@spectrum-css/textfield@^3.0.1":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.0.2.tgz#907f62d2dc82852dd6236a820be99e252b531631"
|
||||||
|
integrity sha512-nkFgAb0cP4jUodkUBErMNfyF78jJLtgL1Mrr9/rvGpGobo10IAbb8zZY4CkZ64o8XmMy/85+wZTKcx+KHatqpg==
|
||||||
|
|
||||||
|
"@spectrum-css/toast@^3.0.1":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.3.tgz#97c1527384707600832ecda35643ed304615250f"
|
||||||
|
integrity sha512-CjLeaMs+cjUXojCCRtbj0YkD2BoZW16kjj2o5omkEpUTjA34IJ8xJ1a+CCtDILWekhXvN0MBN4sbumcnwcnx8w==
|
||||||
|
|
||||||
|
"@spectrum-css/tooltip@^3.0.3":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.0.3.tgz#26b8ca3b3d30e29630244d85eb4fc11d0c841281"
|
||||||
|
integrity sha512-ztRF7WW1FzyNavXBRc+80z67UoOrY9wl3cMYsVD3MpDnyxdzP8cjza1pCcolKBaFqRTcQKkxKw3GWtGICRKR5A==
|
||||||
|
|
||||||
|
"@spectrum-css/treeview@^3.0.2":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046"
|
||||||
|
integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw==
|
||||||
|
|
||||||
|
"@spectrum-css/typography@^3.0.1", "@spectrum-css/typography@^3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38"
|
||||||
integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA==
|
integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA==
|
||||||
|
|
||||||
|
"@spectrum-css/underlay@^2.0.9":
|
||||||
|
version "2.0.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.10.tgz#8b75b646605a311850f6620caa18d4996cd64ed7"
|
||||||
|
integrity sha512-PmsmkzeGD/rY4pp3ILXHt9w8BW7uaEqXe08hQRS7rGki7wqCpG4mE0/8N3yEcA3QxWQclmG9gdkg5uz6wMmYzA==
|
||||||
|
|
||||||
"@spectrum-css/vars@^3.0.1", "@spectrum-css/vars@^3.0.2":
|
"@spectrum-css/vars@^3.0.1", "@spectrum-css/vars@^3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999"
|
||||||
|
@ -78,7 +296,7 @@ colorette@^1.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
|
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
|
||||||
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
|
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
|
||||||
|
|
||||||
dayjs@^1.10.5:
|
dayjs@^1.10.4, dayjs@^1.10.5:
|
||||||
version "1.10.6"
|
version "1.10.6"
|
||||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63"
|
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63"
|
||||||
integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==
|
integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==
|
||||||
|
@ -219,6 +437,11 @@ svelte-hmr@^0.14.7:
|
||||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.7.tgz#7fa8261c7b225d9409f0a86f3b9ea5c3ca6f6607"
|
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.7.tgz#7fa8261c7b225d9409f0a86f3b9ea5c3ca6f6607"
|
||||||
integrity sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==
|
integrity sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==
|
||||||
|
|
||||||
|
svelte-portal@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3"
|
||||||
|
integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q==
|
||||||
|
|
||||||
svelte@^3.38.2:
|
svelte@^3.38.2:
|
||||||
version "3.42.1"
|
version "3.42.1"
|
||||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.42.1.tgz#d4b4d9068cce911835f7c6b8ff1d290e1a0b5657"
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.42.1.tgz#d4b4d9068cce911835f7c6b8ff1d290e1a0b5657"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/string-templates",
|
"name": "@budibase/string-templates",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"description": "Handlebars wrapper for Budibase templating.",
|
"description": "Handlebars wrapper for Budibase templating.",
|
||||||
"main": "src/index.cjs",
|
"main": "src/index.cjs",
|
||||||
"module": "dist/bundle.mjs",
|
"module": "dist/bundle.mjs",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/worker",
|
"name": "@budibase/worker",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "0.9.105-alpha.32",
|
"version": "0.9.116-alpha.3",
|
||||||
"description": "Budibase background service",
|
"description": "Budibase background service",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -23,8 +23,8 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/auth": "^0.9.105-alpha.32",
|
"@budibase/auth": "^0.9.116-alpha.3",
|
||||||
"@budibase/string-templates": "^0.9.105-alpha.32",
|
"@budibase/string-templates": "^0.9.116-alpha.3",
|
||||||
"@koa/router": "^8.0.0",
|
"@koa/router": "^8.0.0",
|
||||||
"@techpass/passport-openidconnect": "^0.3.0",
|
"@techpass/passport-openidconnect": "^0.3.0",
|
||||||
"aws-sdk": "^2.811.0",
|
"aws-sdk": "^2.811.0",
|
||||||
|
|
Loading…
Reference in New Issue