Feature/admin forth/1155/backend validation function le#511
Feature/admin forth/1155/backend validation function le#511SerVitasik merged 35 commits intonextfrom
Conversation
| }); | ||
| isValidating.value = false; | ||
| isValid.value = checkIfAnyColumnHasErrors(); | ||
| }, 500); |
There was a problem hiding this comment.
Do we need to add ability set debounce period?
…aveRecord function
…ge picker, instead of library
…minForth/1334/lets-try-to-improve-styles-for
…minForth/1155/backend-validation-function-le
adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Adds support for backend-driven per-column validation via a custom validator callback, and wires the SPA create/edit flows to wait for async validation results before allowing saves.
Changes:
- Extend column
validationrules to support a customvalidatorcallback and expose validator presence to the frontend. - Add
/validate_columnsREST endpoint and integrate it into SPA create/edit validation flow (including UI spinners and error display). - Refactor duplicated create/edit helpers into
createEditUtilsand update docs + dependency locks.
Reviewed changes
Copilot reviewed 12 out of 14 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| adminforth/types/Common.ts | Adds validator to ValidationObject typing (backend custom validation hook). |
| adminforth/modules/restApi.ts | Exposes validator presence in /get_resource and adds /validate_columns endpoint. |
| adminforth/spa/src/views/EditView.vue | Updates save button state/spinner and uses shared save-prep helper. |
| adminforth/spa/src/views/CreateView.vue | Updates save button state/spinner and uses shared save-prep helper. |
| adminforth/spa/src/components/ResourceForm.vue | Tracks isValidating + columnsWithErrors and triggers backend validation. |
| adminforth/spa/src/components/GroupsTable.vue | Passes validation state/errors down and updates required icon styling. |
| adminforth/spa/src/components/ColumnValueInputWrapper.vue | Renders validation error + spinner near inputs during async validation. |
| adminforth/spa/src/utils/createEditUtils.ts | New shared helpers for “scroll to invalid field” + save preparations. |
| adminforth/spa/src/utils/index.ts | Re-exports new create/edit helpers. |
| adminforth/spa/src/utils.ts | Re-exports new create/edit helpers (legacy barrel). |
| adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md | Updates validation documentation with frontend vs backend validator guidance. |
| adminforth/spa/package.json | Adds async-mutex and lodash.debounce dependencies. |
| adminforth/spa/pnpm-lock.yaml | Lock updates for new deps and minor version bumps. |
| adminforth/spa/package-lock.json | Lock updates for new deps and minor version bumps. |
Files not reviewed (2)
- adminforth/spa/package-lock.json: Language not supported
- adminforth/spa/pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (2)
adminforth/spa/src/views/CreateView.vue:226
saveRecordPreparationscan returnundefinedwhen the form is invalid, butsaveRecord()continues and dereferencesinterceptorsResult.extra, then proceeds to call/create_record. This can both throw at runtime and allow submitting invalid data. Add an early return wheninterceptorsResultis falsy and also checkinterceptorsResult.ok(similar to the previous implementation) before continuing.
async function saveRecord() {
const interceptorsResult = await saveRecordPreparations(
'create',
validatingMode,
resourceFormRef,
isValid,
t,
saving,
runSaveInterceptors,
record,
coreStore,
route
);
const requiredColumns = coreStore.resource?.columns.filter(c => c.required?.create === true) || [];
const requiredColumnsToSkip = requiredColumns.filter(c => checkShowIf(c, record.value, coreStore.resource?.columns || []) === false);
const interceptorConfirmationResult = (interceptorsResult.extra as Record<string, any>)?.confirmationResult;
const response = await callAdminForthApi({
method: 'POST',
path: `/create_record`,
body: {
resourceId: route.params.resourceId,
record: record.value,
requiredColumnsToSkip,
meta: {
...(interceptorConfirmationResult ? { confirmationResult: interceptorConfirmationResult } : {}),
},
},
});
adminforth/spa/src/views/EditView.vue:203
saveRecordPreparationsmay returnundefinedwhen validation fails, butsaveRecord()immediately accessesinterceptorsResult.ok. Guard against a falsy return value (early return) before checking.okto avoid a runtime exception when the record is invalid.
async function saveRecord() {
const interceptorsResult = await saveRecordPreparations(
'edit',
validatingMode,
resourceFormRef,
isValid,
t,
saving,
runSaveInterceptors,
record,
coreStore,
route
);
if (!interceptorsResult.ok) {
saving.value = false;
if (interceptorsResult.error) showErrorTost(interceptorsResult.error);
return;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| delete columnsWithErrors.value[columnName]; | ||
| } | ||
| } | ||
| const columnsToProcess = editableColumns.value.filter(col => res.validationResults[col.name] === undefined); |
There was a problem hiding this comment.
In validateUsingUserValidationFunction, columnsToProcess is derived from editableColumns.value instead of the editableColumnsInner array that was actually validated and sent to the backend. If editableColumns changes while the request is in-flight (e.g., due to showIf changes), this can apply/clear errors for a different set of columns than the response corresponds to. Use editableColumnsInner (or the columns argument passed into the debounced function) when computing columnsToProcess.
| const columnsToProcess = editableColumns.value.filter(col => res.validationResults[col.name] === undefined); | |
| const columnsToProcess = editableColumnsInner.filter(col => res.validationResults[col.name] === undefined); |
adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md
Outdated
Show resolved
Hide resolved
| ], | ||
| ``` | ||
|
|
||
| >Better avoid using of custom validator, because every time change field (after failed first save attempt), it will make an API call |
There was a problem hiding this comment.
The warning sentence is ungrammatical and a bit unclear: "Better avoid using of custom validator, because every time change field...". Rephrase to something like "Avoid using a custom validator because every time you change a field...".
| >Better avoid using of custom validator, because every time change field (after failed first save attempt), it will make an API call | |
| >Avoid using a custom validator because every time you change a field (after a failed first save attempt), it will make an API call. |
| import { type AdminForthComponentDeclarationFull } from '@/types/Common.js'; | ||
| import type { AdminForthResourceColumn } from '@/types/Back'; | ||
| import { scrollToInvalidField, saveRecordPreparations } from '@/utils'; | ||
| import { Spinner } from '@/afcl' |
There was a problem hiding this comment.
There are several imports that are now unused after moving validation helpers to saveRecordPreparations (e.g., scrollToInvalidField, AdminForthResourceColumn, and also watch/nextTick/computed which are only imported). These will be flagged by the SPA ESLint config; please remove the unused imports.
…y-to-improve-styles-for Feature/admin forth/1334/lets try to improve styles for
…minForth/1155/backend-validation-function-le
… ValidationObject - Refactored the applyRegexValidation function to improve readability by storing the regExp in a variable before usage. - Made the regExp and message properties optional in the ValidationObject type to allow for more flexible validation scenarios. - Cleaned up imports in CreateView.vue by removing unused imports to enhance code clarity and maintainability. https://web.tracklify.com/project/2b7ZVgE5/AdminForth/1155/9bItdaNO/backend-validation-function-le
…on and lock files
No description provided.