Prevent invalid characters in column names when importing tables
This commit is contained in:
parent
6a125aadc0
commit
5d0918a6cb
|
@ -47,7 +47,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
{#if tooltip && showTooltip}
|
{#if tooltip && showTooltip}
|
||||||
<div class="tooltip" in:fade={{ duration: 130, delay: 250 }}>
|
<div class="tooltip" in:fade={{ duration: 130, delay: 250 }}>
|
||||||
<Tooltip textWrapping direction="bottom" text={tooltip} />
|
<Tooltip textWrapping direction="top" text={tooltip} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,15 +80,9 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
top: calc(100% + 4px);
|
bottom: calc(100% + 4px);
|
||||||
width: 100vw;
|
|
||||||
max-width: 150px;
|
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
z-index: 1;
|
||||||
|
|
||||||
.spectrum-Icon--sizeXS {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
import { getBindings } from "components/backend/DataTable/formula"
|
import { getBindings } from "components/backend/DataTable/formula"
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import JSONSchemaModal from "./JSONSchemaModal.svelte"
|
import JSONSchemaModal from "./JSONSchemaModal.svelte"
|
||||||
|
import { ValidColumnNameRegex } from "@budibase/shared-core"
|
||||||
|
|
||||||
const AUTO_TYPE = "auto"
|
const AUTO_TYPE = "auto"
|
||||||
const FORMULA_TYPE = FIELDS.FORMULA.type
|
const FORMULA_TYPE = FIELDS.FORMULA.type
|
||||||
|
@ -379,7 +380,7 @@
|
||||||
const newError = {}
|
const newError = {}
|
||||||
if (!external && fieldInfo.name?.startsWith("_")) {
|
if (!external && fieldInfo.name?.startsWith("_")) {
|
||||||
newError.name = `Column name cannot start with an underscore.`
|
newError.name = `Column name cannot start with an underscore.`
|
||||||
} else if (fieldInfo.name && !fieldInfo.name.match(/^[_a-zA-Z0-9\s]*$/g)) {
|
} else if (fieldInfo.name && !fieldInfo.name.match(ValidColumnNameRegex)) {
|
||||||
newError.name = `Illegal character; must be alpha-numeric.`
|
newError.name = `Illegal character; must be alpha-numeric.`
|
||||||
} else if (PROHIBITED_COLUMN_NAMES.some(name => fieldInfo.name === name)) {
|
} else if (PROHIBITED_COLUMN_NAMES.some(name => fieldInfo.name === name)) {
|
||||||
newError.name = `${PROHIBITED_COLUMN_NAMES.join(
|
newError.name = `${PROHIBITED_COLUMN_NAMES.join(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select } from "@budibase/bbui"
|
import { Select, Icon } from "@budibase/bbui"
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { parseFile } from "./utils"
|
import { parseFile } from "./utils"
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
let loading = false
|
let loading = false
|
||||||
let validation = {}
|
let validation = {}
|
||||||
let validateHash = ""
|
let validateHash = ""
|
||||||
|
let errors = {}
|
||||||
|
|
||||||
export let rows = []
|
export let rows = []
|
||||||
export let schema = {}
|
export let schema = {}
|
||||||
|
@ -69,18 +70,20 @@
|
||||||
|
|
||||||
async function validate(rows, schema) {
|
async function validate(rows, schema) {
|
||||||
loading = true
|
loading = true
|
||||||
error = null
|
|
||||||
validation = {}
|
|
||||||
allValid = false
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (rows.length > 0) {
|
if (rows.length > 0) {
|
||||||
const response = await API.validateNewTableImport({ rows, schema })
|
const response = await API.validateNewTableImport({ rows, schema })
|
||||||
validation = response.schemaValidation
|
validation = response.schemaValidation
|
||||||
allValid = response.allValid
|
allValid = response.allValid
|
||||||
|
errors = response.errors
|
||||||
|
error = null
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e.message
|
error = e.message
|
||||||
|
validation = {}
|
||||||
|
allValid = false
|
||||||
|
errors = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
loading = false
|
loading = false
|
||||||
|
@ -147,16 +150,22 @@
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class={loading || validation[column.name]
|
class={validation[column.name]
|
||||||
? "fieldStatusSuccess"
|
? "fieldStatusSuccess"
|
||||||
: "fieldStatusFailure"}
|
: "fieldStatusFailure"}
|
||||||
>
|
>
|
||||||
{validation[column.name] ? "Success" : "Failure"}
|
{#if validation[column.name]}
|
||||||
|
Success
|
||||||
|
{:else}
|
||||||
|
Failure
|
||||||
|
<Icon name="Help" tooltip={errors[column.name]} />
|
||||||
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
<i
|
<Icon
|
||||||
class={`omit-button ri-close-circle-fill ${
|
size="S"
|
||||||
loading ? "omit-button-disabled" : ""
|
name="Close"
|
||||||
}`}
|
disabled={loading}
|
||||||
|
hoverable
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
delete schema[column.name]
|
delete schema[column.name]
|
||||||
schema = schema
|
schema = schema
|
||||||
|
@ -237,23 +246,16 @@
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fieldStatusFailure {
|
.fieldStatusFailure {
|
||||||
color: var(--red);
|
color: var(--red);
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
.fieldStatusFailure :global(.spectrum-Icon) {
|
||||||
.omit-button {
|
width: 12px;
|
||||||
font-size: 1.2em;
|
|
||||||
color: var(--grey-7);
|
|
||||||
cursor: pointer;
|
|
||||||
justify-self: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.omit-button-disabled {
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 70%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-column {
|
.display-column {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { FieldTypes } from "../constants"
|
import { FieldTypes } from "../constants"
|
||||||
|
import { ValidColumnNameRegex } from "@budibase/shared-core"
|
||||||
|
|
||||||
interface SchemaColumn {
|
interface SchemaColumn {
|
||||||
readonly name: string
|
readonly name: string
|
||||||
|
@ -27,6 +28,7 @@ interface ValidationResults {
|
||||||
schemaValidation: SchemaValidation
|
schemaValidation: SchemaValidation
|
||||||
allValid: boolean
|
allValid: boolean
|
||||||
invalidColumns: Array<string>
|
invalidColumns: Array<string>
|
||||||
|
errors: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
const PARSERS: any = {
|
const PARSERS: any = {
|
||||||
|
@ -69,6 +71,7 @@ export function validate(rows: Rows, schema: Schema): ValidationResults {
|
||||||
schemaValidation: {},
|
schemaValidation: {},
|
||||||
allValid: false,
|
allValid: false,
|
||||||
invalidColumns: [],
|
invalidColumns: [],
|
||||||
|
errors: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
|
@ -79,6 +82,11 @@ export function validate(rows: Rows, schema: Schema): ValidationResults {
|
||||||
// If the columnType is not a string, then it's not present in the schema, and should be added to the invalid columns array
|
// If the columnType is not a string, then it's not present in the schema, and should be added to the invalid columns array
|
||||||
if (typeof columnType !== "string") {
|
if (typeof columnType !== "string") {
|
||||||
results.invalidColumns.push(columnName)
|
results.invalidColumns.push(columnName)
|
||||||
|
} else if (!columnName.match(ValidColumnNameRegex)) {
|
||||||
|
// Check for special characters in column names
|
||||||
|
results.invalidColumns.push(columnName)
|
||||||
|
results.errors[columnName] =
|
||||||
|
"Column names can't contain special characters"
|
||||||
} else if (
|
} else if (
|
||||||
columnData == null &&
|
columnData == null &&
|
||||||
!schema[columnName].constraints?.presence
|
!schema[columnName].constraints?.presence
|
||||||
|
|
|
@ -89,3 +89,4 @@ export enum BuilderSocketEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SocketSessionTTL = 60
|
export const SocketSessionTTL = 60
|
||||||
|
export const ValidColumnNameRegex = /^[_a-zA-Z0-9\s]*$/g
|
||||||
|
|
Loading…
Reference in New Issue