refactor(form-intakes): improve form intakes architecture (#18274) - #18314
Octave (OctaveLaventure) wants to merge 38 commits into
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lizer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Task B2's type-check surfaced 5 pre-existing TS2345 errors in Task B1's new validateFormSchemaMappings test fixtures: unannotated object-literal spreads let mainEntityFieldMode widen to string instead of narrowing to the 'multiple' | 'parsed' union, so passing them to validateFormSchemaMappings (FormBuilderData) failed to type-check. Runtime behavior was unaffected (tests passed at runtime), but yarn check-ts was broken. Annotate each fixture as FormBuilderData to restore a clean type-check.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…actor - Remove unused normalizeDraftAuthorizedMembersDefaults import from FormSchemaEditor.tsx, left behind after Task D2 moved its only usage into DraftDefaultsSection.tsx (fixes a yarn lint CI failure) - Harden fieldRendererRegistry with Object.create(null) so unknown field.type values (e.g. 'constructor', 'toString') cannot resolve to inherited Object.prototype members instead of falling back to the registry's 'default' renderer, which previously crashed React - Apply yarn lint --fix formatting corrections triggered by the above changes (import-newlines, indentation) with no behavior changes - Add a regression test asserting the registry does not leak Object.prototype members for unknown field types
…ndle-builder call sites Addresses a Data Clump smell flagged in code review: all 6 call sites of materializeEntityFromFields in form-bundle-builder.ts built a near-identical MaterializeOptions object inline. Adds buildMaterializeOptions(isBypass, overrides) in form-entity-materializer.ts, centralizing the 3 defaults shared by every branch (applyFields: true, skipEmptyFieldValues: false, applyTypeDefaults: true) while requiring each call site to still pass errorLabel and any per-branch override explicitly, preserving the deliberate per-branch skip-empty/type-default asymmetry rather than collapsing it into a generic enum/mode that would misleadingly imply the branches are equivalent.
…move className prop explosion
…form-intake-arch)
…an (#form-intake-arch)
…bility rules (#form-intake-arch)
…uplicating rules 3x (#form-intake-arch)
…(#form-intake-arch)
…de effects (#form-intake-arch)
…bmission (#form-intake-arch)
…r map (#form-intake-arch)
… (#form-intake-arch)
- form-entity-materializer-test.ts: cast through unknown to access the dynamically-applied 'details' field, which is not a declared StoreEntity property (tsc error TS2339). - FormSchemaEditor.tsx: collapse the FormUtils import back to a single line (import-newlines/enforce requires single-line imports for <=20 elements).
…ion gate failures - Mark Switch/TextField imports in DraftDefaultsSection.tsx and MainEntitySection.tsx as fds:keep-mui, consistent with sibling extracted section components (these imports predate this PR). - Migrate fileFieldRenderer.tsx's file-chip from MUI Chip to the design system Chip (onDelete is supported natively). - Update fds-migration/migration-state.json's Checkbox adoption-site entry to point at primitiveFieldRenderers.tsx, where the checkbox rendering now lives after the field-renderer registry extraction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ew findings (#18274) - planSubmission: wrap buildDraftPlan in the same try/catch shape commitSubmission uses, so a failure while building the draft plan is logged and surfaced as a FunctionalError like it was before the planSubmission/commitSubmission split, instead of propagating raw. - fileFieldRenderer.tsx: clarify the 'Stays MUI' comment so it clearly scopes to the native file input widget only, not the file-list Chip below (which already uses the design-system Chip). - useFormBuilderOperations: document that toggleParsedMode assumes a strictly binary fieldMode ('multiple' | 'parsed'). - FormViewUtils computeDraftPolicy: remove the dead 'author.type === static && defaultValue' clause from author.initialized -- FormView.tsx already special-cases that combination in its own branch before checking initialized, so the clause never affected behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Refactors Form Intake architecture across backend submission/materialization and frontend form editing/rendering while preserving behavior.
Changes:
- Splits submission planning from side effects and extracts draft planning.
- Replaces entity-source branching with adapters and centralizes materialization.
- Extracts frontend policies, operations, renderers, and adds tests.
Reviewed changes
Copilot reviewed 43 out of 44 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| opencti-platform/opencti-graphql/tests/01-unit/modules/forms/form-entity-materializer-test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-graphql/tests/01-unit/modules/forms/form-bundle-builder-test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-graphql/tests/01-unit/domain/form-plan-submission-test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-graphql/tests/01-unit/domain/form-draft-plan-test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-graphql/tests/01-unit/domain/form-commit-submission-test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-graphql/src/modules/form/form-entity-materializer.ts | Updated as part of this pull request. |
| opencti-platform/opencti-graphql/src/modules/form/form-domain.ts | Updated as part of this pull request. |
| opencti-platform/opencti-graphql/src/modules/form/form-bundle-builder.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/FormViewUtils.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/FormViewUtils.test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/FormView.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/FormFieldRenderer.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/types.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/types.test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/registry.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/registry.test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/primitiveFieldRenderers.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/primitiveFieldRenderers.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/fileFieldRenderer.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/fileFieldRenderer.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/dateAndReferenceFieldRenderers.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/dateAndReferenceFieldRenderers.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/choiceFieldRenderers.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/choiceFieldRenderers.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/useFormSchemaEditorStyles.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/useFormBuilderOperations.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/useFormBuilderOperations.test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/useFieldRenderer.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/RelationshipsSection.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/RelationshipsSection.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/MainEntitySection.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/MainEntitySection.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/FormUtils.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/FormUtils.test.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/FormEdition.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/FormCreation.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/Form.d.ts | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/DraftDefaultsSection.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/DraftDefaultsSection.test.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/AdditionalEntitiesSection.tsx | Updated as part of this pull request. |
| opencti-platform/opencti-front/src/private/components/data/forms/AdditionalEntitiesSection.test.tsx | Updated as part of this pull request. |
| fds-migration/migration-state.json | Updated as part of this pull request. |
Suppressed comments (3)
opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/dateAndReferenceFieldRenderers.tsx:128
- The external-reference renderer has the same dotted-name lookup problem: for parsed/multiple overrides
fieldValuebecomes'', so creating an external reference does not preserve the current nested list and may pass a non-array value toappend. Read the value throughgetNestedValue(values, fieldName)with the simple-key fallback.
const fieldValue = fieldPrefix ? getNestedValue(values, fieldName) : (values[field.name] || '');
opencti-platform/opencti-front/src/private/components/data/forms/view/fieldRenderers/fileFieldRenderer.tsx:115
- The new removable chip relies on the design system's default delete label, which is an untranslated
Remove ${label}. In non-English locales, screen-reader users will hear English for this control; the existingTagwrapper documents that callers must provide a translateddeleteLabel. Pass a translated delete label here as well.
<Chip
key={index}
label={file.name ?? ''}
onDelete={() => handleFileRemove(index)}
opencti-platform/opencti-graphql/src/modules/form/form-domain.ts:521
- The new planning boundary is not actually pure or I/O-free as described: these calls load entities, can invoke the pattern-conversion service, build relationships, and line 521 logs the generated bundle. Every
planSubmissioncall still depends on external state and performs side effects beforecommitSubmission; either move those effects behind the commit-time plan or narrow the documented contract to no submission writes.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…#18274) Fixes bugs and cleans up duplication flagged by automated and human review on the form intake architecture refactor: - Always resolve dotted-path field names via getNestedValue instead of falling back to a literal values[field.name] lookup, which broke whenever the field name itself contained a dot (object label, external references, file attachment fields). - Fix fileFieldRenderer using the unprefixed field name when calling setFieldValue on upload/remove, and add a translated delete label to the attachment Chip for accessibility. - Normalize the two conflicting setFieldValue contracts (relative vs. fully-qualified path) behind a single scopedSetFieldValue wrapper in FormFieldRenderer, fixing a double-prefixing bug affecting CreatedBy/ObjectMarking/ObjectLabel/ExternalReferences fields on additional entities and relationships. - Change toggleParsedMode to take an explicit target mode instead of flipping the current one, fixing a bug where an omitted (legacy) fieldMode always flipped to parsed regardless of the option actually selected in the UI. - Extract removeFieldsSupersededByParsedMapping into FormUtils and use it from both MainEntitySection and AdditionalEntitiesSection, removing duplicated field-removal logic. - Extract a shared SPECIAL_ATTRIBUTE_FIELD_TYPE map in useFieldRenderer and use it in both the available-field-types computation and the attribute-selection handler, removing the duplicated special-attribute switch. - Make RelationshipsSection update/toggle callbacks required props and remove the redundant handleFieldChange-based fallback implementations that duplicated the same mutation logic. - Extract a shared FieldRendererInput base interface reused by FieldRendererContext and FormFieldRendererProps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… log side-effect (#18274) Address review feedback that planSubmission was documented as a pure decision step but still performs DB reads, may invoke a Python pattern-conversion bridge, and generates a bundle id. Narrow the JSDoc to accurately describe the function as side-effect-free for writes (no persistence, no logging) without claiming full purity/determinism, and move the "[FORM] STIX Bundle generated" log call out of planSubmission into commitSubmission where the actual orchestration and persistence happen. Also rewrite the misleading "builds a bundle with objects" unit test, which asserted nothing about bundle contents, to instead verify that buildMainStixEntities/buildAdditionalEntities/buildRelationships/ wrapInContainerOrPush are invoked with the expected arguments. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report❌ Patch coverage is ❌ Your patch check has failed because the patch coverage (65.86%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## master #18314 +/- ##
==========================================
+ Coverage 35.46% 37.46% +2.00%
==========================================
Files 3428 3486 +58
Lines 139424 148068 +8644
Branches 37734 40624 +2890
==========================================
+ Hits 49444 55474 +6030
- Misses 89980 92594 +2614
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Description
Deepens the Form Intake feature's architecture (both frontend form editing and backend form ingestion, draft and non-draft modes) per the 5 candidates identified in an
/improve-codebase-architecturereview. Pure refactor, no observable behavior change.Closes #18274
Backend
buildDraftPlan: centralizes the draft-mode choreography previously inlined informSubmit's draft branch (form-domain.ts).planSubmission/commitSubmission: splitsformSubmitinto a pure decision step (planSubmission: builds the bundle/draft plan, no I/O) and an execution step (commitSubmission: work creation, queue push, patch, telemetry).formSubmitis now a thin 2-call composition.EntitySourceAdaptermap: extractsbuildMainStixEntities's 4 source-mode branches (lookup, multiple, parsed, default) into aRecord<Mode, EntitySourceAdapter>map + a mode resolver, preserving every per-branchbuildMaterializeOptionsasymmetry exactly.Frontend
computeDraftPolicy: centralizes draft field visibility/required/validation rules that were previously duplicated 3x inFormView.tsx(init values, Yup validation, render conditions) into a single computedDraftPolicy.useFormBuilderOperations: introduces namedFormBuilderDataoperations (renameField,toggleParsedMode,addAdditionalEntity,updateRelationshipEntity,updateRelationshipType,toggleRelationshipRequired) replacing the primary uses of the generichandleFieldChange(path, value)string-path walker. Genuinely dynamic/generic settings paths remain onhandleFieldChangeby design.How to test this PR
Backend:
cd opencti-platform/opencti-graphql yarn test:ci-unit yarn check-tsFrontend:
cd opencti-platform/opencti-front yarn vitest run src/private/components/data/forms yarn check-tsManually, verify form creation/edition and form submission (draft and non-draft) still behave identically:
Notes