wip refactor manifest
This commit is contained in:
parent
e08d745360
commit
cd36056124
10 changed files with 201 additions and 227 deletions
|
@ -26,6 +26,8 @@
|
||||||
export let tag = null
|
export let tag = null
|
||||||
export let searchTerm = null
|
export let searchTerm = null
|
||||||
export let loading
|
export let loading
|
||||||
|
export let onOptionMouseenter = () => {}
|
||||||
|
export let onOptionMouseleave = () => {}
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
@ -95,6 +97,8 @@
|
||||||
{autocomplete}
|
{autocomplete}
|
||||||
{sort}
|
{sort}
|
||||||
{tag}
|
{tag}
|
||||||
|
{onOptionMouseenter}
|
||||||
|
{onOptionMouseleave}
|
||||||
isPlaceholder={value == null || value === ""}
|
isPlaceholder={value == null || value === ""}
|
||||||
placeholderOption={placeholder === false ? null : placeholder}
|
placeholderOption={placeholder === false ? null : placeholder}
|
||||||
isOptionSelected={option => compareOptionAndValue(option, value)}
|
isOptionSelected={option => compareOptionAndValue(option, value)}
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
export let tag = null
|
export let tag = null
|
||||||
export let helpText = null
|
export let helpText = null
|
||||||
export let compare
|
export let compare
|
||||||
|
export let onOptionMouseenter = () => {}
|
||||||
|
export let onOptionMouseleave = () => {}
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const onChange = e => {
|
const onChange = e => {
|
||||||
value = e.detail
|
value = e.detail
|
||||||
|
@ -67,6 +70,8 @@
|
||||||
{customPopoverHeight}
|
{customPopoverHeight}
|
||||||
{tag}
|
{tag}
|
||||||
{compare}
|
{compare}
|
||||||
|
{onOptionMouseenter}
|
||||||
|
{onOptionMouseleave}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
on:click
|
on:click
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default as FieldContext } from "./FieldContext.svelte"
|
||||||
|
export * from "./validator"
|
|
@ -17,8 +17,7 @@ export const constants = {
|
||||||
supported: Symbol("values-validator-supported")
|
supported: Symbol("values-validator-supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
export const validators = {
|
export const validate = (fieldSchema) => {
|
||||||
chart: (fieldSchema) => {
|
|
||||||
try {
|
try {
|
||||||
const response = {
|
const response = {
|
||||||
level: null,
|
level: null,
|
||||||
|
@ -79,4 +78,3 @@ export const validators = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
|
@ -1,25 +1,32 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select } from "@budibase/bbui"
|
import { Select, ContextTooltip } from "@budibase/bbui"
|
||||||
import { getDatasourceForProvider, getSchemaForDatasource } from "dataBinding"
|
import { getDatasourceForProvider, getSchemaForDatasource } from "dataBinding"
|
||||||
import { selectedScreen } from "stores/builder"
|
import { selectedScreen } from "stores/builder"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { validators, constants as validatorConstants } from "../fieldValidator";
|
import { FieldContext, validate } from './FieldContext'
|
||||||
|
import { debounce } from "lodash"
|
||||||
|
import { goto, params } from "@roxi/routify"
|
||||||
|
import { Constants } from "@budibase/frontend-core"
|
||||||
|
import { FIELDS } from 'constants/backend'
|
||||||
|
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let value = ""
|
export let value = ""
|
||||||
export let placeholder
|
export let placeholder
|
||||||
export let fieldValidator
|
export let columnContext
|
||||||
|
|
||||||
const getFieldSupport = (schema, fieldValidator) => {
|
let contextTooltipAnchor = null
|
||||||
if (fieldValidator == null) {
|
let currentOption = null
|
||||||
|
let previousOption = null
|
||||||
|
let contextTooltipVisible = false
|
||||||
|
|
||||||
|
const getFieldSupport = (schema, columnContext) => {
|
||||||
|
if (!columnContext) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const validator = validators[fieldValidator];
|
|
||||||
|
|
||||||
const fieldSupport = {}
|
const fieldSupport = {}
|
||||||
Object.entries(schema || {}).forEach(([key, value]) => {
|
Object.entries(schema || {}).forEach(([key, value]) => {
|
||||||
fieldSupport[key] = validator(value)
|
fieldSupport[key] = validate(value)
|
||||||
})
|
})
|
||||||
|
|
||||||
return fieldSupport
|
return fieldSupport
|
||||||
|
@ -28,7 +35,7 @@
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
$: datasource = getDatasourceForProvider($selectedScreen, componentInstance)
|
$: datasource = getDatasourceForProvider($selectedScreen, componentInstance)
|
||||||
$: schema = getSchemaForDatasource($selectedScreen, datasource).schema
|
$: schema = getSchemaForDatasource($selectedScreen, datasource).schema
|
||||||
$: fieldSupport = getFieldSupport(schema, fieldValidator);
|
$: fieldSupport = getFieldSupport(schema, columnContext);
|
||||||
$: options = Object.keys(schema || {})
|
$: options = Object.keys(schema || {})
|
||||||
$: boundValue = getValidValue(value, options)
|
$: boundValue = getValidValue(value, options)
|
||||||
|
|
||||||
|
@ -51,34 +58,87 @@
|
||||||
dispatch("change", boundValue)
|
dispatch("change", boundValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getOptionIcon = option => {
|
const updateTooltip = debounce((e, option) => {
|
||||||
/*
|
if (option == null) {
|
||||||
const support = fieldSupport[option]?.support;
|
contextTooltipVisible = false;
|
||||||
|
} else {
|
||||||
|
contextTooltipAnchor = e?.target;
|
||||||
|
previousOption = currentOption;
|
||||||
|
currentOption = option;
|
||||||
|
contextTooltipVisible = true;
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
|
||||||
if (support == null) return null;
|
const onOptionMouseenter = (e, option, idx) => {
|
||||||
if (support === supported) return null
|
updateTooltip(e, option);
|
||||||
|
|
||||||
if (support === partialSupport) return "Warning"
|
|
||||||
if (support === unsupported) return "Error"
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getOptionIconTooltip = option => {
|
const onOptionMouseleave = (e, option) => {
|
||||||
|
updateTooltip(e, null);
|
||||||
|
}
|
||||||
|
const getOptionIcon = optionKey => {
|
||||||
|
const option = schema[optionKey]
|
||||||
|
if (!option) return ""
|
||||||
|
|
||||||
|
if (option.autocolumn) {
|
||||||
|
return "MagicWand"
|
||||||
|
}
|
||||||
|
const { type, subtype } = option
|
||||||
|
|
||||||
|
const result =
|
||||||
|
typeof Constants.TypeIconMap[type] === "object" && subtype
|
||||||
|
? Constants.TypeIconMap[type][subtype]
|
||||||
|
: Constants.TypeIconMap[type]
|
||||||
|
|
||||||
|
return result || "Text"
|
||||||
}
|
}
|
||||||
|
|
||||||
const isOptionEnabled = option => {
|
const getOptionIconTooltip = optionKey => {
|
||||||
return true
|
const option = schema[optionKey]
|
||||||
const support = fieldSupport[option]?.support;
|
|
||||||
|
|
||||||
if (support == null) return true
|
const type = option?.type;
|
||||||
if (support == unsupported) return false
|
const field = Object.values(FIELDS).find(f => f.type === type)
|
||||||
|
|
||||||
return true
|
if (field) {
|
||||||
|
return field.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
{isOptionEnabled}
|
{placeholder}
|
||||||
{getOptionIcon}
|
value={boundValue}
|
||||||
{getOptionIconTooltip}
|
on:change={onChange}
|
||||||
{placeholder} value={boundValue} on:change={onChange} {options} />
|
{options}
|
||||||
|
{onOptionMouseenter}
|
||||||
|
{onOptionMouseleave}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if columnContext}
|
||||||
|
<ContextTooltip
|
||||||
|
visible={contextTooltipVisible}
|
||||||
|
anchor={contextTooltipAnchor}
|
||||||
|
offset={20}
|
||||||
|
>
|
||||||
|
<FieldContext
|
||||||
|
explanationModal
|
||||||
|
tableHref={`/builder/app/${$params.application}/data/table/${datasource?.tableId}`}
|
||||||
|
schema={schema[currentOption]}
|
||||||
|
support={fieldSupport[currentOption]}
|
||||||
|
columnIcon={getOptionIcon(currentOption)}
|
||||||
|
columnName={currentOption}
|
||||||
|
columnType={getOptionIconTooltip(currentOption)}
|
||||||
|
/>
|
||||||
|
<FieldContext
|
||||||
|
slot="previous"
|
||||||
|
schema={schema[previousOption]}
|
||||||
|
support={fieldSupport[previousOption]}
|
||||||
|
columnIcon={getOptionIcon(previousOption)}
|
||||||
|
columnName={previousOption}
|
||||||
|
columnType={getOptionIconTooltip(previousOption)}
|
||||||
|
/>
|
||||||
|
</ContextTooltip>
|
||||||
|
{/if}
|
||||||
|
|
|
@ -1,54 +1,39 @@
|
||||||
<script>
|
<script>
|
||||||
import { Icon, Heading, Multiselect, ContextTooltip } from "@budibase/bbui"
|
import { Icon, Heading, Multiselect, ContextTooltip } from "@budibase/bbui"
|
||||||
import { getDatasourceForProvider, getSchemaForDatasource } from "dataBinding"
|
import { getDatasourceForProvider, getSchemaForDatasource } from "dataBinding"
|
||||||
import { selectedScreen } from "stores/builder"
|
import { selectedScreen,
|
||||||
|
componentStore,
|
||||||
|
} from "stores/builder"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { validators } from "./FieldContext/Validator";
|
import { FieldContext, validate } from './FieldContext'
|
||||||
import ChartFieldContext from './FieldContext/Chart.svelte'
|
|
||||||
import { FIELDS } from 'constants/backend'
|
import { FIELDS } from 'constants/backend'
|
||||||
import { goto, params } from "@roxi/routify"
|
import { goto, params } from "@roxi/routify"
|
||||||
import { debounce } from "lodash"
|
import { debounce } from "lodash"
|
||||||
|
import { Constants } from "@budibase/frontend-core"
|
||||||
|
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let value = ""
|
export let value = ""
|
||||||
export let placeholder
|
export let placeholder
|
||||||
export let fieldValidator
|
export let columnContext
|
||||||
|
export let valueTypes
|
||||||
|
|
||||||
let contextTooltipAnchor = null
|
let contextTooltipAnchor = null
|
||||||
let currentOption = null
|
let currentOption = null
|
||||||
let previousOption = null
|
let previousOption = null
|
||||||
let contextTooltipVisible = false
|
let contextTooltipVisible = false
|
||||||
|
|
||||||
const TypeIconMap = {
|
$: componentDefinition = componentStore.getDefinition(
|
||||||
text: "Text",
|
componentInstance?._component
|
||||||
options: "Dropdown",
|
)
|
||||||
datetime: "Date",
|
|
||||||
barcodeqr: "Camera",
|
|
||||||
longform: "TextAlignLeft",
|
|
||||||
array: "Dropdown",
|
|
||||||
number: "123",
|
|
||||||
boolean: "Boolean",
|
|
||||||
attachment: "AppleFiles",
|
|
||||||
link: "DataCorrelated",
|
|
||||||
formula: "Calculator",
|
|
||||||
json: "Brackets",
|
|
||||||
bigint: "TagBold",
|
|
||||||
bb_reference: {
|
|
||||||
user: "User",
|
|
||||||
users: "UserGroup",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFieldSupport = (schema, fieldValidator) => {
|
const getFieldSupport = (schema, columnContext) => {
|
||||||
if (fieldValidator == null) {
|
if (!columnContext) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const validator = validators[fieldValidator];
|
|
||||||
|
|
||||||
const fieldSupport = {}
|
const fieldSupport = {}
|
||||||
Object.entries(schema || {}).forEach(([key, value]) => {
|
Object.entries(schema || {}).forEach(([key, value]) => {
|
||||||
fieldSupport[key] = validator(value)
|
fieldSupport[key] = validate(value)
|
||||||
})
|
})
|
||||||
|
|
||||||
return fieldSupport
|
return fieldSupport
|
||||||
|
@ -58,7 +43,7 @@
|
||||||
$: datasource = getDatasourceForProvider($selectedScreen, componentInstance)
|
$: datasource = getDatasourceForProvider($selectedScreen, componentInstance)
|
||||||
$: schema = getSchemaForDatasource($selectedScreen, datasource).schema
|
$: schema = getSchemaForDatasource($selectedScreen, datasource).schema
|
||||||
$: options = Object.keys(schema || {})
|
$: options = Object.keys(schema || {})
|
||||||
$: fieldSupport = getFieldSupport(schema, fieldValidator);
|
$: fieldSupport = getFieldSupport(schema, columnContext);
|
||||||
$: boundValue = getValidOptions(value, options)
|
$: boundValue = getValidOptions(value, options)
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,9 +70,9 @@
|
||||||
const { type, subtype } = option
|
const { type, subtype } = option
|
||||||
|
|
||||||
const result =
|
const result =
|
||||||
typeof TypeIconMap[type] === "object" && subtype
|
typeof Constants.TypeIconMap[type] === "object" && subtype
|
||||||
? TypeIconMap[type][subtype]
|
? Constants.TypeIconMap[type][subtype]
|
||||||
: TypeIconMap[type]
|
: Constants.TypeIconMap[type]
|
||||||
|
|
||||||
return result || "Text"
|
return result || "Text"
|
||||||
}
|
}
|
||||||
|
@ -139,7 +124,6 @@
|
||||||
|
|
||||||
<Multiselect
|
<Multiselect
|
||||||
iconPosition="right"
|
iconPosition="right"
|
||||||
{isOptionEnabled}
|
|
||||||
{placeholder}
|
{placeholder}
|
||||||
value={boundValue}
|
value={boundValue}
|
||||||
on:change={setValue}
|
on:change={setValue}
|
||||||
|
@ -148,12 +132,14 @@
|
||||||
{onOptionMouseenter}
|
{onOptionMouseenter}
|
||||||
{onOptionMouseleave}
|
{onOptionMouseleave}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{#if columnContext}
|
||||||
<ContextTooltip
|
<ContextTooltip
|
||||||
visible={contextTooltipVisible}
|
visible={contextTooltipVisible}
|
||||||
anchor={contextTooltipAnchor}
|
anchor={contextTooltipAnchor}
|
||||||
offset={20}
|
offset={20}
|
||||||
>
|
>
|
||||||
<ChartFieldContext
|
<FieldContext
|
||||||
explanationModal
|
explanationModal
|
||||||
tableHref={`/builder/app/${$params.application}/data/table/${datasource?.tableId}`}
|
tableHref={`/builder/app/${$params.application}/data/table/${datasource?.tableId}`}
|
||||||
schema={schema[currentOption]}
|
schema={schema[currentOption]}
|
||||||
|
@ -162,7 +148,7 @@
|
||||||
columnName={currentOption}
|
columnName={currentOption}
|
||||||
columnType={getOptionIconTooltip(currentOption)}
|
columnType={getOptionIconTooltip(currentOption)}
|
||||||
/>
|
/>
|
||||||
<ChartFieldContext
|
<FieldContext
|
||||||
slot="previous"
|
slot="previous"
|
||||||
schema={schema[previousOption]}
|
schema={schema[previousOption]}
|
||||||
support={fieldSupport[previousOption]}
|
support={fieldSupport[previousOption]}
|
||||||
|
@ -171,6 +157,4 @@
|
||||||
columnType={getOptionIconTooltip(previousOption)}
|
columnType={getOptionIconTooltip(previousOption)}
|
||||||
/>
|
/>
|
||||||
</ContextTooltip>
|
</ContextTooltip>
|
||||||
|
{/if}
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
import { capitalize } from 'lodash';
|
|
||||||
|
|
||||||
export const errors = {
|
|
||||||
general: Symbol("values-validator-general"),
|
|
||||||
jsonPrimitivesOnly: Symbol("values-validator-json-primitives-only"),
|
|
||||||
}
|
|
||||||
|
|
||||||
export const warnings = {
|
|
||||||
stringAsNumber: Symbol("values-validator-string-as-number"),
|
|
||||||
chartDatetime: Symbol("values-validator-chart-datetime"),
|
|
||||||
notRequired: Symbol("values-validator-not-required"),
|
|
||||||
}
|
|
||||||
|
|
||||||
export const constants = {
|
|
||||||
unsupported: Symbol("values-validator-unsupported"),
|
|
||||||
partialSupport: Symbol("values-validator-partialSupport"),
|
|
||||||
supported: Symbol("values-validator-supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
export const validators = {
|
|
||||||
chart: (fieldSchema) => {
|
|
||||||
try {
|
|
||||||
const response = {
|
|
||||||
level: null,
|
|
||||||
warnings: [],
|
|
||||||
errors: [],
|
|
||||||
text: "",
|
|
||||||
icon: "",
|
|
||||||
iconColor: ""
|
|
||||||
}
|
|
||||||
const generalUnsupportedFields = ["array", "attachment", "barcodeqr", "link", "bb_reference"]
|
|
||||||
if (generalUnsupportedFields.includes(fieldSchema.type)) {
|
|
||||||
response.errors.push(errors.general)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldSchema.type === "json") {
|
|
||||||
response.errors.push(errors.jsonPrimitivesOnly)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldSchema.type === "string") {
|
|
||||||
response.warnings.push(warnings.stringAsNumber)
|
|
||||||
}
|
|
||||||
if (fieldSchema.type === "datetime") {
|
|
||||||
response.warnings.push(warnings.chartDatetime);
|
|
||||||
//"This column can be used as an input for a chart, but it may be parsed differently depending on which is used.
|
|
||||||
}
|
|
||||||
|
|
||||||
const isRequired = fieldSchema?.constraints?.presence?.allowEmpty === false
|
|
||||||
if (!isRequired) {
|
|
||||||
response.warnings.push(warnings.notRequired);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.errors.length > 0) {
|
|
||||||
response.level = constants.unsupported
|
|
||||||
response.text = "Not compatible"
|
|
||||||
response.icon = "Alert"
|
|
||||||
response.iconColor = "var(--red)"
|
|
||||||
} else if (response.warnings.length > 0) {
|
|
||||||
response.level = constants.partialSupport
|
|
||||||
response.text = "Partially compatible"
|
|
||||||
response.icon = "AlertCheck"
|
|
||||||
response.iconColor = "var(--yellow)"
|
|
||||||
} else {
|
|
||||||
response.level = constants.supported
|
|
||||||
response.text = "Compatible"
|
|
||||||
response.icon = "CheckmarkCircle"
|
|
||||||
response.iconColor = "var(--green)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
} catch (e) {
|
|
||||||
return {
|
|
||||||
level: constants.partialSupport,
|
|
||||||
warnings: [],
|
|
||||||
errors: [],
|
|
||||||
text: "Partially compatible",
|
|
||||||
icon: "AlertCheck",
|
|
||||||
iconColor: "var(--yellow)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -193,7 +193,8 @@
|
||||||
max: setting.max ?? null,
|
max: setting.max ?? null,
|
||||||
|
|
||||||
// Field select settings
|
// Field select settings
|
||||||
fieldValidator: setting.fieldValidator,
|
columnContext: setting.columnContext,
|
||||||
|
valueTypes: setting.valueTypes
|
||||||
}}
|
}}
|
||||||
{bindings}
|
{bindings}
|
||||||
{componentBindings}
|
{componentBindings}
|
||||||
|
|
|
@ -1602,6 +1602,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"bar": {
|
"bar": {
|
||||||
|
"documentationLink": "https://docs.budibase.com/docs/bar-chart",
|
||||||
"name": "Bar Chart",
|
"name": "Bar Chart",
|
||||||
"description": "Bar chart",
|
"description": "Bar chart",
|
||||||
"icon": "GraphBarVertical",
|
"icon": "GraphBarVertical",
|
||||||
|
@ -1633,7 +1634,8 @@
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumns",
|
"key": "valueColumns",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
"fieldValidator": "chart",
|
"valueTypes": ["number"],
|
||||||
|
"columnContext": true,
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue