[Cases] Add global reusable field definitions#269962
Open
lgestc wants to merge 33 commits into
Open
Conversation
Adds a `renderInAllCases` boolean to `FieldDefinition` so field-library entries can be flagged as global — appearing in every case view and create form regardless of template selection, with values stored in `extended_fields` using the same key format as template-specific fields. - Domain/API: `renderInAllCases?: boolean` on `FieldDefinitionSchema` and `FieldDefinitionsFindRequest` filter; SO mappings updated to match. - Server: `create.ts` and `validators.ts` relax extended_fields validation to allow keys that correspond to `renderInAllCases: true` field defs even when no template is set; `resolveGlobalFieldKeys` helper fetches and parses global defs server-side. - Field library UI: `renderInAllCases` checkbox (with tooltip) in the definition flyout; badge column on the all-definitions page. - Case view: new `GlobalCaseFields` component renders global fields in the sidebar, independent of `TemplateFields`. - Case create: `CreateCaseTemplateFields` always renders global fields; `useTemplateFormSync` preserves their values across template switches. - Tests: flyout checkbox, service filter, validators allow-logic, create form global fields path — all green; i18n check passes (4 new keys). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When `template: null` clears a template on update, extended_fields containing only renderInAllCases keys were incorrectly rejected. The no-template path now applies uniformly — global keys are always permitted regardless of whether the template is absent or being cleared; non-global keys are still rejected in both cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs prevented renderInAllCases fields from appearing in the create case form when no template was picked: 1. useTemplateFormSync returned isLoading:true indefinitely when no templateId was set, because react-query keeps a disabled query in loading state when there is no cached data. Fixed by short-circuiting isLoading to false whenever templateId is absent. 2. CreateCaseTemplateFields rendered the "Template not selected" callout even when global fields were already visible, suppressing the FormProvider wrapper. Fixed by skipping the callout when global inline fields are present. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix createFormSerializer reading the wrong key: the form stores extended fields under the camelCase key 'extendedFields' (schema field) but the serializer was destructuring 'extended_fields'. Also fix createFormDeserializer to map 'extended_fields' → 'extendedFields' when loading existing case data. Tighten CaseFormFieldsSchemaProps to Omit 'extended_fields' from the CasePostRequest base to avoid the ambiguity entirely. - Change "Render in all cases" label/column text to "Apply to all cases" to match the applyToAllCases field name, and rename the TS translation constants accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n, tests - Extract `parseFieldDefinitionsToInlineFields` to `common/utils/template_fields.ts` so the YAML→InlineField parsing is shared between client and server instead of duplicated in three places - Fix N+1 query: `validateExtendedFieldsInRequest` now receives a pre-resolved `globalKeys: Set<string>` instead of calling `fieldDefinitionsService` per case inside `Promise.all`; `bulk_update.ts` resolves keys once per unique owner - Add `modelVersion1` to the `case-field-definition` saved-object type to register the `applyToAllCases` mapping with Elasticsearch - Add unit tests for `parseFieldDefinitionsToInlineFields`, `GlobalCaseFields` component, and `create.ts` extended_fields validation paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Pinging @elastic/kibana-cases (Team:Cases) |
The jest.mock for './template_fields' only stubbed TemplateFields but not GlobalCaseFields, which was added in this PR. Rendering undefined as a component triggered the error boundary in the test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- client.ts: throw 400 when getFieldDefinitions is called with no owner, preventing trivially-passing auth check on empty entities array - client.ts: add comment documenting that field definition mutations intentionally produce no UserAction (library-level objects, not case mutations) - get_field_definitions_route.ts: coerce applyToAllCases query param from string "true" to boolean — HTTP query params arrive as strings, causing the service filter to never apply - use_get_field_definitions.ts: skip query when no owner provided, preventing unnecessary 400 errors when template has not loaded yet - model_version_1.ts: add data_backfill to set applyToAllCases: false on pre-existing field definition documents - template_fields.tsx: check isError in GlobalCaseFields and CreateCaseTemplateFields to distinguish query error from empty results - use_template_form_sync.test.ts: add tests covering globalFieldKeys preservation across template switch and template deselection - template_fields.test.tsx: add test for GlobalCaseFields isError state - client.test.ts: add getFieldDefinitions tests covering the empty-owner guard Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… the active template When a field definition has both applyToAllCases: true and is referenced via \$ref in the active template, it was previously rendered twice — once in the global fields section and once in the template section. The template may apply name/default overrides via the \$ref entry, so the template section owns display for those fields. GlobalCaseFields and the global section in the create form now exclude any field whose name appears as a \$ref in the active template. globalFieldKeys remains unfiltered so useTemplateFormSync still preserves values for those fields across template switches. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Incorporate main's HiddenField registration for CASE_EXTENDED_FIELDS while preserving the branch's expanded loading condition and refactored globalFieldsFragment/templateFieldsFragment structure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nded fields heading in case view - Gate isLoadingFields on templateId to avoid react-query v4's indefinite loading state for disabled queries blocking global-field render - Add "Extended fields" section header in case view to match "Global fields" - Fix GlobalCaseFields excessive padding by wrapping in a single div so it appears as one flex item in the gutterSize="xl" column Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eedback - Remove client-side merge in processExtendedFields; each form section now sends only its own fields to prevent last-write-wins race conditions - Add server-side merge in createPatchCasesPayload using originalCase attributes so concurrent GlobalCaseFields / TemplateFields saves don't overwrite each other - Fix boolean coercion in getFieldDefinitionsRoute (false was treated as undefined) - Add JSDoc to resolveGlobalFieldKeys explaining unsecured SO access is safe - Add visibility comment to casesRedesign config block in server/index.ts - Add explanatory comment to modelVersion1 data_backfill defaulting logic - Update tests to assert only section-own fields are sent (not merged set) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add API integration tests for applyToAllCases filter, create/patch cases with global extended_fields, and server-side merge behavior - Add comment to FieldDefinitionsFindRequestSchema explaining the boolean/string coercion gap at the HTTP route layer - Add comment to FieldDefinitionsService explaining that applyToAllCases false and undefined are both no-op (no filter added) - Add comment in CreateCaseTemplateFields explaining why owner[0] is safe Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…renders Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… fix save and dedup - GlobalCaseFields renders without a section title and is moved to appear before CustomFields in the sidebar - TemplateFields filters out inline fields whose name collides with a global field definition, preventing duplicate entries when a template and the global field library share the same field name - validateExtendedFields gains a partial option (used in the update path) that skips the required check for fields absent from the request, fixing 400 errors when saving only global fields on a case that has a template with required fields Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…anges - TemplateFields tests: add default mockUseGetFieldDefinitions return value in beforeEach now that TemplateFields calls useGetFieldDefinitions - GlobalCaseFields test: update assertion to expect no 'Global fields' title - validators test: update required-field test to explicitly clear the field (empty string) rather than omitting it; add a test covering the partial update case where only global fields are provided Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…iew sidebar Both were direct children of the xl-gutter flex column, causing an oversized gap. Wrapping them in a div makes them a single flex item. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add staleTime: Infinity to global field defs fetch in CreateCaseTemplateFields so background refetches don't recreate the Set reference and reset the form - Expose staleTime option on useGetFieldDefinitions hook - GlobalCaseFields renders "Extended fields" heading when no template is active - Document orphaned extended_fields merge behaviour in bulk_update - Add JSDoc to FieldDefinitionsService.getFieldDefinitions explaining the applyToAllCases: false / undefined equivalence - Add applyToAllCases passthrough unit test in field definitions sub-client - Add per-owner global key isolation tests in bulk_update (N+1 prevention and cross-owner key rejection) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
💛 Build succeeded, but was flaky
Failed CI Steps
Test Failures
Metrics [docs]Async chunks
Page load bundle
History
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an
applyToAllCasesflag to field library definitions so that specific fields appear in every case — in both the create form and the case view sidebar — regardless of which template (if any) is selected. Values are stored inextended_fieldsusing the same key format as template-specific fields, so no separate storage mechanism is needed.Motivation
Teams with many templates often need the same contextual fields (e.g. incident type, severity tier, business unit) on every case, not just on cases created from a particular template. Without this flag, those fields had to be duplicated into every template definition. This flag lets a field be defined once in the library and surface everywhere automatically.
Changes
applyToAllCases?: booleanadded toFieldDefinitionSchemaand theGET /fieldsquery filter; SO mapping updated to match.create.tsandvalidators.ts(bulk update path) now allowextended_fieldskeys that correspond toapplyToAllCases: truedefinitions even when no template is set. Non-global keys without a template still reject as before.GlobalCaseFieldscomponent renders global fields in the sidebar, independently of the existingTemplateFieldscomponent (which remains unchanged).CreateCaseTemplateFieldsalways fetches and renders global fields;useTemplateFormSyncpreserves their values when the user switches or clears a template.Risk & Migration
Score: 2 — Optional boolean field on a brand-new SO type with no existing production documents; no exported public API surfaces changed; all validation changes are backward-compatible (existing cases without
applyToAllCasesdefs are unaffected). Gated behind the existingtemplates.enabledconfig flag.Testing
Manual:
templates.enabledflag inkibana.dev.yml.Automated:
server/services/field_definitions/index.test.ts— filter logic forapplyToAllCasesserver/client/cases/validators.test.ts— allow/reject logic for global vs. non-global keyspublic/components/field_library/components/field_definition_flyout.test.tsx— checkbox state andonSavepayloadpublic/components/create/template_fields.test.tsx— global fields render pathpublic/components/create/use_template_form_sync.test.ts— value preservation across template switchesChecklist
Check the PR satisfies following conditions.
Reviewers should verify this PR satisfies this list as well.
release_note:breakinglabel should be applied in these situations.release_note:*label is applied per the guidelinesbackport:*labels.