多维表格
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.1 KiB

Nc feat/form validation (#8409) * feat(nc-gui): custom validation setup * fix(nc-gui): custom validation table rounded issue * fix: add custom field validation type * fix(nc-gui): updated custom validator * feat(nc-gui): custom validation working state * fix(nc-gui): udpate default warning msg * chore(nc-gui): lint * fix(nc-gui): grayed out errors if input is focused * fix(nc-gui): input ring issue * fix(nc-gui): increase max height of validator select dropdown * fix(nc-gui): validator select dropdown item text color * fix(nc-gui): regex validation condition update * fix(nc-gui): add missing string validation types * fix(nc-gui): remove unwanted code * fix(nc-gui): move custom validation to ee * refacor(nc-gui): form view code * refactor(nc-gui): separate out formviewstore for ce & ee * fix(nc-gui): move all validations to another file * feat(nc-gui): add validation input component * feat(nc-gui): add time, month types * fix(nc-gui): add form field limit validations * fix(nc-gui): add limit link record validation * fix(nc-gui): add phonenumber & url validation type * feat(nc-gui): add email, url & phone number validators * fix(nc-gui): non working phone, email, url validation * chore(nc-giu): lint * feat(nc-gui): add attchment type validation * chore(nc-gui): lint * fix(nc-gui): add form field validation in shared form * fix(nc-gui): add form field validation in shared form oss * fix(nc-gui): oss validation conflict * fix(nc-gui): enter number validation function * fix(nc-gui): add config validators * fix(nc-gui): validation config error handling * fix(nc-gui): placeholder issue * fix(nc-gui): custom validation config error handling * fix(nc-gui): allow negative value validation * fix(nc-gui): add tooltip for required field switch * fix(nc-gui): refactor field validation from builder side * chore(nc-gui): lint * fix(nc-gui): update number validation logic * fix(nc-gui): rating field alignment issue * fix(nc-gui): small changes * fix(nc-gui): required field validation issue * fix(nc-gui): allow click on title to enable field config * feat(nc-gui): business email validation support * fix(nc-gui): add remove image btn in cell itself * fix(nc-gui): small changes * fix(nc-gui): survey form required field validation issue * fix(nc-gui): error field border issue * fix(nc-gui): currency validation input cell prefix issue * fix(nc-gui): remove console * chore(nc-gui): lint * fix: information text * fix(nc-gui): remove contains & doesn't contain option from phone number custom validation * fix(nc-gui): attachment merge conflict * fix(nc-gui): attachment cell expand btn size * fix(nc-gui): PR review changes * fix(nc-gui): lint * fix(nc-gui): updated form config heading text color * fix(nc-gui): small changes --------- Co-authored-by: Raju Udava <86527202+dstala@users.noreply.github.com>
6 months ago
import type { Ref } from 'vue'
import type { RuleObject } from 'ant-design-vue/es/form'
import type { ColumnType, FormType, TableType, ViewType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isLinksOrLTAR } from 'nocodb-sdk'
const useForm = Form.useForm
const [useProvideFormViewStore, useFormViewStore] = useInjectionState(
(
_meta: Ref<TableType | undefined> | ComputedRef<TableType | undefined>,
viewMeta: Ref<ViewType | undefined> | ComputedRef<(ViewType & { id: string }) | undefined>,
formViewData: Ref<FormType | undefined>,
updateFormView: (view: FormType | undefined) => Promise<any>,
isEditable: boolean,
) => {
const { $api } = useNuxtApp()
const { t } = useI18n()
const formResetHook = createEventHook<void>()
const formState = ref<Record<string, any>>({})
const localColumns = ref<Record<string, any>[]>([])
const activeRow = ref('')
const visibleColumns = computed(() => localColumns.value.filter((f) => f.show).sort((a, b) => a.order - b.order))
const activeField = computed(() => visibleColumns.value.find((c) => c.id === activeRow.value) || null)
const activeColumn = computed(() => {
if (_meta.value && activeField.value) {
if (_meta.value.columnsById && (_meta.value.columnsById as Record<string, ColumnType>)[activeField.value?.fk_column_id]) {
return (_meta.value.columnsById as Record<string, ColumnType>)[activeField.value.fk_column_id]
} else if (_meta.value.columns) {
return _meta.value.columns.find((c) => c.id === activeField.value?.fk_column_id) ?? null
}
}
return null
})
const validators = computed(() => {
const rulesObj: Record<string, RuleObject[]> = {}
if (!visibleColumns.value) return rulesObj
for (const column of visibleColumns.value) {
let rules: RuleObject[] = [
{
required: isRequired(column, column.required),
message: t('msg.error.fieldRequired'),
...(column.uidt === UITypes.Checkbox && isRequired(column, column.required) ? { type: 'enum', enum: [1, true] } : {}),
},
]
const additionalRules = extractFieldValidator(parseProp(column.meta).validators ?? [], column)
rules = [...rules, ...additionalRules]
if (rules.length) {
rulesObj[column.title!] = rules
}
}
return rulesObj
})
// Form field validation
const { validate, validateInfos, clearValidate } = useForm(formState, validators)
const validateActiveField = async (col: ColumnType) => {
try {
await validate(col.title)
} catch {}
}
const updateView = useDebounceFn(
() => {
updateFormView(formViewData.value)
},
300,
{ maxWait: 2000 },
)
const updateColMeta = useDebounceFn(async (col: Record<string, any>) => {
if (col.id && isEditable) {
validateActiveField(col)
try {
await $api.dbView.formColumnUpdate(col.id, col)
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
}, 250)
function isRequired(_columnObj: Record<string, any>, required = false) {
let columnObj = _columnObj
if (isLinksOrLTAR(columnObj.uidt) && columnObj.colOptions && columnObj.colOptions.type === RelationTypes.BELONGS_TO) {
columnObj = (_meta?.value?.columns || []).find(
(c: Record<string, any>) => c.id === columnObj.colOptions.fk_child_column_id,
) as Record<string, any>
}
return required || (columnObj && columnObj.rqd && !columnObj.cdf)
}
return {
onReset: formResetHook.on,
formState,
localColumns,
visibleColumns,
activeRow,
activeField,
activeColumn,
isRequired,
updateView,
updateColMeta,
validate,
validateInfos,
clearValidate,
}
},
'form-view-store',
)
export { useProvideFormViewStore }
export function useFormViewStoreOrThrow() {
const sharedFormStore = useFormViewStore()
if (sharedFormStore == null) throw new Error('Please call `useProvideFormViewStore` on the appropriate parent component')
return sharedFormStore
}