feat: Implement NOT NULL validation for form fields based on table metadata

- Added a new function `isColumnRequired` to determine if a column is required based on its NOT NULL status from the table schema.
- Updated the `SaveModal` and `InteractiveScreenViewer` components to incorporate this validation, ensuring that required fields are accurately assessed during form submission.
- Enhanced the `DynamicComponentRenderer` to reflect the NOT NULL requirement in the component's required state.
- Improved user feedback by marking required fields with an asterisk based on both manual settings and database constraints.

These changes enhance the form validation process, ensuring that users are prompted for all necessary information based on the underlying data structure.
This commit is contained in:
kjs
2026-03-10 14:16:02 +09:00
parent c0eab878a1
commit 43523a0bba
13 changed files with 138 additions and 76 deletions

View File

@@ -11,7 +11,7 @@ import { ComponentData, WidgetComponent, DataTableComponent, FileComponent, Butt
import { FileUploadComponent } from "@/lib/registry/components/file-upload/FileUploadComponent";
import { InteractiveDataTable } from "./InteractiveDataTable";
import { DynamicWebTypeRenderer } from "@/lib/registry";
import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer";
import { DynamicComponentRenderer, isColumnRequiredByMeta } from "@/lib/registry/DynamicComponentRenderer";
import { filterDOMProps } from "@/lib/utils/domPropsFilter";
import { isFileComponent, isDataTableComponent, isButtonComponent } from "@/lib/utils/componentTypeUtils";
import { FlowButtonGroup } from "./widgets/FlowButtonGroup";
@@ -1294,9 +1294,8 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
...(labelPos === "bottom" ? { marginTop: style?.labelMarginBottom || "4px" } : {}),
}}
>
{labelText}
{((component as any).required || (component as any).componentConfig?.required) && (
<span className="ml-1 text-destructive">*</span>
{labelText}{((component as any).required || (component as any).componentConfig?.required || isColumnRequiredByMeta((component as any).tableName, (component as any).columnName)) && (
<span className="text-orange-500">*</span>
)}
</label>
) : null;
@@ -1349,9 +1348,8 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
whiteSpace: "nowrap",
}}
>
{labelText}
{((component as any).required || (component as any).componentConfig?.required) && (
<span className="ml-1 text-destructive">*</span>
{labelText}{((component as any).required || (component as any).componentConfig?.required || isColumnRequiredByMeta((component as any).tableName, (component as any).columnName)) && (
<span className="text-orange-500">*</span>
)}
</label>
<div style={{ width: "100%", height: "100%" }}>