Chart Component and Explanation Modal Fixes and Improvements (#13922)

* wip

* wip refactoring icons and column names

* wip

* wip

* remove automatic chart datetime sorting

* indefinite article, long form text

* lint

* lint
This commit is contained in:
Gerard Burns 2024-06-14 08:20:56 +01:00 committed by GitHub
parent 5367696abd
commit d47c7d9227
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 127 additions and 140 deletions

View File

@ -18,14 +18,11 @@
import subjects from "./subjects"
import { appStore } from "stores/builder"
export let explanation
export let columnIcon
export let columnType
export let columnName
export let tableHref = () => {}
export let schema
export let name
export let explanation
export let componentName
$: explanationWithPresets = getExplanationWithPresets(
explanation,
@ -54,14 +51,8 @@
</script>
<div bind:this={root} class="tooltipContents">
<Column
{columnName}
{columnIcon}
{columnType}
{tableHref}
{setExplanationSubject}
/>
<Support {support} {setExplanationSubject} />
<Column {name} {schema} {tableHref} {setExplanationSubject} />
<Support {componentName} {support} {setExplanationSubject} />
{#if messages.includes(messageConstants.stringAsNumber)}
<StringAsNumber {setExplanationSubject} />
{/if}
@ -84,7 +75,7 @@
{#if detailsModalSubject !== subjects.none}
<DetailsModal
{columnName}
columnName={name}
anchor={root}
{schema}
subject={detailsModalSubject}

View File

@ -1,69 +1,124 @@
<script>
import {
Line,
InfoWord,
DocumentationLink,
Text,
Period,
} from "../typography"
import { Line, InfoWord, DocumentationLink, Text } from "../typography"
import { FieldType } from "@budibase/types"
import { FIELDS } from "constants/backend"
import subjects from "../subjects"
export let columnName
export let columnIcon
export let columnType
export let schema
export let name
export let tableHref
export let setExplanationSubject
const getTypeName = schema => {
const fieldDefinition = Object.values(FIELDS).find(
f => f.type === schema?.type
)
if (schema?.type === "jsonarray") {
return "JSON Array"
}
if (schema?.type === "options") {
return "Options"
}
return fieldDefinition?.name || schema?.type || "Unknown"
}
const getTypeIcon = schema => {
const fieldDefinition = Object.values(FIELDS).find(
f => f.type === schema?.type
)
if (schema?.type === "jsonarray") {
return "BracketsSquare"
}
return fieldDefinition?.icon || "Circle"
}
const getDocLink = columnType => {
if (columnType === "Number") {
if (columnType === FieldType.NUMBER) {
return "https://docs.budibase.com/docs/number"
}
if (columnType === "Text") {
if (columnType === FieldType.STRING) {
return "https://docs.budibase.com/docs/text"
}
if (columnType === "Attachment") {
if (columnType === FieldType.LONGFORM) {
return "https://docs.budibase.com/docs/text"
}
if (columnType === FieldType.ATTACHMENT_SINGLE) {
return "https://docs.budibase.com/docs/attachments"
}
if (columnType === "Multi-select") {
if (columnType === FieldType.ATTACHMENTS) {
// No distinct multi attachment docs, link to attachment instead
return "https://docs.budibase.com/docs/attachments"
}
if (columnType === FieldType.ARRAY) {
return "https://docs.budibase.com/docs/multi-select"
}
if (columnType === "JSON") {
if (columnType === FieldType.JSON) {
return "https://docs.budibase.com/docs/json"
}
if (columnType === "Date/Time") {
if (columnType === "jsonarray") {
return "https://docs.budibase.com/docs/json"
}
if (columnType === FieldType.DATETIME) {
return "https://docs.budibase.com/docs/datetime"
}
if (columnType === "User") {
return "https://docs.budibase.com/docs/user"
if (columnType === FieldType.BB_REFERENCE_SINGLE) {
return "https://docs.budibase.com/docs/users-1"
}
if (columnType === "QR") {
if (columnType === FieldType.BB_REFERENCE) {
return "https://docs.budibase.com/docs/users-1"
}
if (columnType === FieldType.BARCODEQR) {
return "https://docs.budibase.com/docs/barcodeqr"
}
if (columnType === "Relationship") {
if (columnType === FieldType.LINK) {
return "https://docs.budibase.com/docs/relationships"
}
if (columnType === "Formula") {
if (columnType === FieldType.FORMULA) {
return "https://docs.budibase.com/docs/formula"
}
if (columnType === "Options") {
if (columnType === FieldType.OPTIONS) {
return "https://docs.budibase.com/docs/options"
}
if (columnType === "BigInt") {
// No BigInt docs
return null
}
if (columnType === "Boolean") {
if (columnType === FieldType.BOOLEAN) {
return "https://docs.budibase.com/docs/boolean-truefalse"
}
if (columnType === "Signature") {
if (columnType === FieldType.SIGNATURE_SINGLE) {
// No Signature docs
return null
}
if (columnType === FieldType.BIGINT) {
// No BigInt docs
return null
}
return null
}
$: docLink = getDocLink(columnType)
// NOTE The correct indefinite article is based on the pronounciation of the word it precedes, not the spelling. So simply checking if the word begins with a vowel is not sufficient.
// e.g., `an honor`, `a user`
const getIndefiniteArticle = schema => {
const anTypes = [
FieldType.OPTIONS,
null, // `null` gets parsed as "unknown"
undefined, // `undefined` gets parsed as "unknown"
]
if (anTypes.includes(schema?.type)) {
return "an"
}
return "a"
}
$: columnTypeName = getTypeName(schema)
$: columnIcon = getTypeIcon(schema)
$: docLink = getDocLink(schema?.type)
$: indefiniteArticle = getIndefiniteArticle(schema)
</script>
<Line noWrap>
@ -71,14 +126,14 @@
on:mouseenter={() => setExplanationSubject(subjects.column)}
on:mouseleave={() => setExplanationSubject(subjects.none)}
href={tableHref}
text={columnName}
text={name}
/>
<Text value=" is a " />
<Text value={` is ${indefiniteArticle} `} />
<DocumentationLink
disabled={docLink === null}
href={docLink}
icon={columnIcon}
text={`${columnType} column`}
text={columnTypeName}
/>
<Period />
<Text value=" column." />
</Line>

View File

@ -2,9 +2,16 @@
import { Line, InfoWord, DocumentationLink, Text } from "../typography"
import subjects from "../subjects"
import * as explanation from "../explanation"
import { componentStore } from "stores/builder"
export let setExplanationSubject
export let support
export let componentName
const getComponentDefinition = componentName => {
const components = $componentStore.components || {}
return components[componentName] || null
}
const getIcon = support => {
if (support === explanation.support.unsupported) {
@ -39,21 +46,24 @@
$: icon = getIcon(support)
$: color = getColor(support)
$: text = getText(support)
$: componentDefinition = getComponentDefinition(componentName)
</script>
<Line>
<InfoWord
on:mouseenter={() => setExplanationSubject(subjects.support)}
on:mouseleave={() => setExplanationSubject(subjects.none)}
{icon}
{color}
{text}
/>
<Text value=" with this " />
<DocumentationLink
href="https://docs.budibase.com/docs/chart"
icon="GraphPie"
text="Chart component"
/>
<Text value=" input." />
</Line>
{#if componentDefinition}
<Line>
<InfoWord
on:mouseenter={() => setExplanationSubject(subjects.support)}
on:mouseleave={() => setExplanationSubject(subjects.none)}
{icon}
{color}
{text}
/>
<Text value=" with this " />
<DocumentationLink
href={componentDefinition.documentationLink}
icon={componentDefinition.icon}
text={componentDefinition.name}
/>
<Text value=" input." />
</Line>
{/if}

View File

@ -6,8 +6,6 @@
import { Explanation } from "./Explanation"
import { debounce } from "lodash"
import { params } from "@roxi/routify"
import { Constants } from "@budibase/frontend-core"
import { FIELDS } from "constants/backend"
export let componentInstance = {}
export let value = ""
@ -60,35 +58,6 @@
const onOptionMouseleave = e => {
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 getOptionIconTooltip = optionKey => {
const option = schema[optionKey]
const type = option?.type
const field = Object.values(FIELDS).find(f => f.type === type)
if (field) {
return field.name
}
return ""
}
</script>
<Select
@ -109,10 +78,9 @@
<Explanation
tableHref={`/builder/app/${$params.application}/data/table/${datasource?.tableId}`}
schema={schema[currentOption]}
columnIcon={getOptionIcon(currentOption)}
columnName={currentOption}
columnType={getOptionIconTooltip(currentOption)}
name={currentOption}
{explanation}
componentName={componentInstance._component}
/>
</ContextTooltip>
{/if}

View File

@ -4,10 +4,8 @@
import { selectedScreen } from "stores/builder"
import { createEventDispatcher } from "svelte"
import { Explanation } from "./Explanation"
import { FIELDS } from "constants/backend"
import { params } from "@roxi/routify"
import { debounce } from "lodash"
import { Constants } from "@budibase/frontend-core"
export let componentInstance = {}
export let value = ""
@ -37,40 +35,6 @@
dispatch("change", boundValue)
}
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 getOptionIconTooltip = optionKey => {
const option = schema[optionKey]
const type = option?.type
const field = Object.values(FIELDS).find(f => f.type === type)
if (field) {
return field.name
} else if (type === "jsonarray") {
// `jsonarray` isn't present in the above FIELDS constant
return "JSON Array"
}
return ""
}
const updateTooltip = debounce((e, option) => {
if (option == null) {
contextTooltipVisible = false
@ -110,10 +74,9 @@
<Explanation
tableHref={`/builder/app/${$params.application}/data/table/${datasource?.tableId}`}
schema={schema[currentOption]}
columnIcon={getOptionIcon(currentOption)}
columnName={currentOption}
columnType={getOptionIconTooltip(currentOption)}
name={currentOption}
{explanation}
componentName={componentInstance._component}
/>
</ContextTooltip>
{/if}

View File

@ -5223,6 +5223,7 @@
]
},
"chartblock": {
"documentationLink": "https://docs.budibase.com/docs/chart",
"block": true,
"name": "Chart Block",
"icon": "GraphPie",

View File

@ -35,6 +35,7 @@
export let valueUnits
export let yAxisLabel
export let xAxisLabel
export let yAxisUnits
export let curve
// Area
@ -85,6 +86,7 @@
valueUnits,
yAxisLabel,
xAxisLabel,
yAxisUnits,
stacked,
horizontal,
curve,

View File

@ -74,7 +74,6 @@
},
},
xaxis: {
type: labelType,
categories,
labels: {
formatter: xAxisFormatter,

View File

@ -72,7 +72,6 @@
},
// We can just always provide the categories to the xaxis and horizontal mode automatically handles "tranposing" the categories to the yaxis, but certain things like labels need to be manually put on a certain axis based on the selected mode. Titles do not need to be handled this way, they are exposed to the user as "X axis" and Y Axis" so flipping them would be confusing.
xaxis: {
type: labelType,
categories,
labels: {
formatter: xAxisFormatter,

View File

@ -66,7 +66,6 @@
},
},
xaxis: {
type: labelType,
categories,
labels: {
formatter: xAxisFormatter,