Merge pull request #13899 from Budibase/cheeks-fixes
Various QoL and table fixes
This commit is contained in:
commit
672d78159e
|
@ -334,7 +334,7 @@
|
|||
// Add in defaults and initial definition
|
||||
const definition = fieldDefinitions[type?.toUpperCase()]
|
||||
if (definition?.constraints) {
|
||||
editableColumn.constraints = definition.constraints
|
||||
editableColumn.constraints = cloneDeep(definition.constraints)
|
||||
}
|
||||
|
||||
editableColumn.type = definition.type
|
||||
|
|
|
@ -38,4 +38,5 @@
|
|||
{processFiles}
|
||||
handleFileTooLarge={$admin.cloud ? handleFileTooLarge : null}
|
||||
{fileSizeLimit}
|
||||
on:change
|
||||
/>
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
const { styleable, builderStore } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
let handlingOnClick = false
|
||||
|
||||
export let disabled = false
|
||||
export let text = ""
|
||||
export let onClick
|
||||
|
@ -19,17 +17,9 @@
|
|||
// For internal use only for now - not defined in the manifest
|
||||
export let active = false
|
||||
|
||||
const handleOnClick = async () => {
|
||||
handlingOnClick = true
|
||||
|
||||
if (onClick) {
|
||||
await onClick()
|
||||
}
|
||||
|
||||
handlingOnClick = false
|
||||
}
|
||||
|
||||
let node
|
||||
let touched = false
|
||||
let handlingOnClick = false
|
||||
|
||||
$: $component.editing && node?.focus()
|
||||
$: componentText = getComponentText(text, $builderStore, $component)
|
||||
|
@ -42,7 +32,18 @@
|
|||
}
|
||||
|
||||
const updateText = e => {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
if (touched) {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
}
|
||||
touched = false
|
||||
}
|
||||
|
||||
const handleOnClick = async () => {
|
||||
handlingOnClick = true
|
||||
if (onClick) {
|
||||
await onClick()
|
||||
}
|
||||
handlingOnClick = false
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -57,6 +58,7 @@
|
|||
on:blur={$component.editing ? updateText : null}
|
||||
bind:this={node}
|
||||
class:active
|
||||
on:input={() => (touched = true)}
|
||||
>
|
||||
{#if icon}
|
||||
<i class="{icon} {size}" />
|
||||
|
|
|
@ -90,9 +90,11 @@
|
|||
columns.forEach((column, idx) => {
|
||||
overrides[column.field] = {
|
||||
displayName: column.label,
|
||||
width: column.width,
|
||||
order: idx,
|
||||
}
|
||||
if (column.width) {
|
||||
overrides[column.field].width = column.width
|
||||
}
|
||||
})
|
||||
return overrides
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
export let size
|
||||
|
||||
let node
|
||||
let touched = false
|
||||
|
||||
$: $component.editing && node?.focus()
|
||||
$: placeholder = $builderStore.inBuilder && !text && !$component.editing
|
||||
|
@ -47,7 +48,10 @@
|
|||
|
||||
// Convert contenteditable HTML to text and save
|
||||
const updateText = e => {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
if (touched) {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
}
|
||||
touched = false
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -62,6 +66,7 @@
|
|||
class:underline
|
||||
class="spectrum-Heading {sizeClass} {alignClass}"
|
||||
on:blur={$component.editing ? updateText : null}
|
||||
on:input={() => (touched = true)}
|
||||
>
|
||||
{componentText}
|
||||
</h1>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
export let size
|
||||
|
||||
let node
|
||||
let touched = false
|
||||
|
||||
$: $component.editing && node?.focus()
|
||||
$: externalLink = url && typeof url === "string" && !url.startsWith("/")
|
||||
|
@ -62,7 +63,10 @@
|
|||
}
|
||||
|
||||
const updateText = e => {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
if (touched) {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
}
|
||||
touched = false
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -76,6 +80,7 @@
|
|||
class:underline
|
||||
class="align--{align || 'left'} size--{size || 'M'}"
|
||||
on:blur={$component.editing ? updateText : null}
|
||||
on:input={() => (touched = true)}
|
||||
>
|
||||
{componentText}
|
||||
</div>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
export let size
|
||||
|
||||
let node
|
||||
let touched = false
|
||||
|
||||
$: $component.editing && node?.focus()
|
||||
$: placeholder = $builderStore.inBuilder && !text && !$component.editing
|
||||
|
@ -46,7 +47,10 @@
|
|||
|
||||
// Convert contenteditable HTML to text and save
|
||||
const updateText = e => {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
if (touched) {
|
||||
builderStore.actions.updateProp("text", e.target.textContent)
|
||||
}
|
||||
touched = false
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -61,6 +65,7 @@
|
|||
class:underline
|
||||
class="spectrum-Body {sizeClass} {alignClass}"
|
||||
on:blur={$component.editing ? updateText : null}
|
||||
on:input={() => (touched = true)}
|
||||
>
|
||||
{componentText}
|
||||
</p>
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
// Register field with form
|
||||
const formApi = formContext?.formApi
|
||||
const labelPos = fieldGroupContext?.labelPosition || "above"
|
||||
|
||||
let touched = false
|
||||
let labelNode
|
||||
|
||||
$: formStep = formStepContext ? $formStepContext || 1 : 1
|
||||
$: formField = formApi?.registerField(
|
||||
field,
|
||||
|
@ -36,14 +40,12 @@
|
|||
validation,
|
||||
formStep
|
||||
)
|
||||
|
||||
$: schemaType =
|
||||
fieldSchema?.type !== "formula" && fieldSchema?.type !== "bigint"
|
||||
? fieldSchema?.type
|
||||
: "string"
|
||||
|
||||
// Focus label when editing
|
||||
let labelNode
|
||||
$: $component.editing && labelNode?.focus()
|
||||
|
||||
// Update form properties in parent component on every store change
|
||||
|
@ -57,7 +59,10 @@
|
|||
$: labelClass = labelPos === "above" ? "" : `spectrum-FieldLabel--${labelPos}`
|
||||
|
||||
const updateLabel = e => {
|
||||
builderStore.actions.updateProp("label", e.target.textContent)
|
||||
if (touched) {
|
||||
builderStore.actions.updateProp("label", e.target.textContent)
|
||||
}
|
||||
touched = false
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
|
@ -79,6 +84,7 @@
|
|||
bind:this={labelNode}
|
||||
contenteditable={$component.editing}
|
||||
on:blur={$component.editing ? updateLabel : null}
|
||||
on:input={() => (touched = true)}
|
||||
class:hidden={!label}
|
||||
class:readonly
|
||||
for={fieldState?.fieldId}
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
}
|
||||
input {
|
||||
flex: 1 1 auto;
|
||||
width: 0;
|
||||
border: none;
|
||||
padding: var(--cell-padding);
|
||||
overflow: hidden;
|
||||
|
|
|
@ -116,7 +116,9 @@
|
|||
{#each displayColumns as column}
|
||||
<div class="column">
|
||||
<Icon size="S" name={getColumnIcon(column)} />
|
||||
{column.label}
|
||||
<div class="column-label" title={column.label}>
|
||||
{column.label}
|
||||
</div>
|
||||
</div>
|
||||
<ToggleActionButtonGroup
|
||||
on:click={e => toggleColumn(column, e.detail)}
|
||||
|
@ -139,7 +141,8 @@
|
|||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 8px;
|
||||
grid-row-gap: 8px;
|
||||
grid-column-gap: 24px;
|
||||
}
|
||||
.columns :global(.spectrum-Switch) {
|
||||
margin-right: 0;
|
||||
|
@ -148,4 +151,11 @@
|
|||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.column-label {
|
||||
min-width: 80px;
|
||||
max-width: 200px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
.permissionPicker {
|
||||
display: flex;
|
||||
gap: var(--spacing-xs);
|
||||
padding-left: calc(var(--spacing-xl) * 2);
|
||||
}
|
||||
|
||||
.permissionPicker :global(.spectrum-Icon) {
|
||||
|
|
|
@ -23,14 +23,24 @@
|
|||
0
|
||||
)
|
||||
|
||||
const updateBounds = () => {
|
||||
bounds.set(body.getBoundingClientRect())
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Observe and record the height of the body
|
||||
const observer = new ResizeObserver(() => {
|
||||
bounds.set(body.getBoundingClientRect())
|
||||
})
|
||||
observer.observe(body)
|
||||
const resizeObserver = new ResizeObserver(updateBounds)
|
||||
resizeObserver.observe(body)
|
||||
|
||||
// Capture any wheel events on the page to ensure our scroll offset is
|
||||
// correct. We don't care about touch events as we only need this for
|
||||
// hovering over rows with a mouse.
|
||||
window.addEventListener("wheel", updateBounds, true)
|
||||
|
||||
// Clean up listeners
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
resizeObserver.disconnect()
|
||||
window.removeEventListener("wheel", updateBounds, true)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -94,6 +94,7 @@ export const createActions = context => {
|
|||
nonPlus,
|
||||
schemaMutations,
|
||||
schema,
|
||||
notifications,
|
||||
} = context
|
||||
|
||||
// Gets the appropriate API for the configured datasource type
|
||||
|
@ -125,16 +126,25 @@ export const createActions = context => {
|
|||
// Saves the datasource definition
|
||||
const saveDefinition = async newDefinition => {
|
||||
// Update local state
|
||||
const originalDefinition = get(definition)
|
||||
definition.set(newDefinition)
|
||||
|
||||
// Update server
|
||||
if (get(config).canSaveSchema) {
|
||||
await getAPI()?.actions.saveDefinition(newDefinition)
|
||||
try {
|
||||
await getAPI()?.actions.saveDefinition(newDefinition)
|
||||
|
||||
// Broadcast change so external state can be updated, as this change
|
||||
// will not be received by the builder websocket because we caused it
|
||||
// ourselves
|
||||
dispatch("updatedatasource", newDefinition)
|
||||
// Broadcast change so external state can be updated, as this change
|
||||
// will not be received by the builder websocket because we caused it
|
||||
// ourselves
|
||||
dispatch("updatedatasource", newDefinition)
|
||||
} catch (error) {
|
||||
const msg = error?.message || error || "Unknown error"
|
||||
get(notifications).error(`Error saving schema: ${msg}`)
|
||||
|
||||
// Reset the definition if saving failed
|
||||
definition.set(originalDefinition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue