Skip to content

[Cases][AttachmentV2] Migrate Lens to unified registry#261407

Merged
christineweng merged 7 commits intoelastic:mainfrom
christineweng:cases-migrate-persistable-1
Apr 13, 2026
Merged

[Cases][AttachmentV2] Migrate Lens to unified registry#261407
christineweng merged 7 commits intoelastic:mainfrom
christineweng:cases-migrate-persistable-1

Conversation

@christineweng
Copy link
Copy Markdown
Contributor

@christineweng christineweng commented Apr 6, 2026

Summary

This PR is part 1 of migrating persistable state attachment type to V2 architecture. Lens is migrated, and other persistable state attachments (such as single metric viewer, more in this ticket) should continue to behave with the feature flag off.

Feature flag: xpack.cases.attachments.enabled: true (restart kibana after turning the flag on/off)

How to test:

  • Lens attachment can be added via dashboards. In Security, go to Dashboard, Overview, click more action to add the lens chart to a case
image
  • Lens added before the change should continue to show
  • Feature flag off: Lens attachment can be added and saved to cases-comments SO
  • Feature flag on: Lens attachment can be added and saved to cases-attachments SO

Note: turning off the feature flag will exclude attachments from the attachments SO, attachments added with flag on and disappearing when the flag is off is expected

Checklist

  • Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support
  • Documentation was added for features that require explanation or tutorials
  • Unit or functional tests were updated or added to match the most common scenarios
  • If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the docker list
  • This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The release_note:breaking label should be applied in these situations.
  • Flaky Test Runner was used on any tests changed
  • The PR description includes the appropriate Release Notes section, and the correct release_note:* label is applied per the guidelines
  • Review the backport guidelines and apply applicable backport:* labels.

@christineweng christineweng self-assigned this Apr 6, 2026
@christineweng christineweng requested review from a team as code owners April 6, 2026 19:26
@christineweng christineweng added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting Team:Cases Security Solution Cases team v9.4.0 labels Apr 6, 2026
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-cases (Team:Cases)

@christineweng christineweng changed the title [Cases][Attachment] Migrate Lens to unified registry [Cases][AttachmentV2] Migrate Lens to unified registry Apr 6, 2026
@christineweng christineweng force-pushed the cases-migrate-persistable-1 branch from ef1545b to acca786 Compare April 7, 2026 19:43
Comment thread x-pack/platform/plugins/shared/cases/common/constants/attachments.ts Outdated
data: {
state: { attributes, timeRange, metadata },
},
} as unknown as UnifiedValueAttachmentWithoutOwner);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think there is a way we can fix this type cast?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lens data contains LensSavedObjectAttributes (from @kbn/lens-plugin/public) which is a deeply nested type with specific Lens-domain properties -- these are structurally incompatible with JsonValue even though they serialize to JSON just fine at runtime.

Since { state: { attributes: LensSavedObjectAttributes, ... } } is not assignable to Record<string, JsonValue>, TypeScript requires the unknown intermediary. There is no way to avoid this without changing either the Lens types or the UnifiedValueAttachmentPayload type definition.

Comment thread x-pack/platform/plugins/shared/cases/public/components/attachments/lens/index.tsx Outdated
@janmonschke
Copy link
Copy Markdown
Contributor

I wonder if we need to update getCommentContent as well now or if an empty string is good enough for lens attachments.

const getCommentContent = (comment: AttachmentV2): string => {
if (isLegacyAttachmentRequest(comment)) {
if (comment.type === AttachmentType.user) {
return comment.comment;
} else if (comment.type === AttachmentType.alert) {
const ids = getAlertIds(comment);
return `Alert with ids ${ids.join(', ')} added to case`;
} else if (
comment.type === AttachmentType.actions &&
(comment.actions.type === 'isolate' || comment.actions.type === 'unisolate')
) {
const firstHostname =
comment.actions.targets?.length > 0 ? comment.actions.targets[0].hostname : 'unknown';
const totalHosts = comment.actions.targets.length;
const actionText = comment.actions.type === 'isolate' ? 'Isolated' : 'Released';
const additionalHostsText = totalHosts - 1 > 0 ? `and ${totalHosts - 1} more ` : ``;
return `${actionText} host ${firstHostname} ${additionalHostsText}with comment: ${comment.comment}`;
}
}
return '';

Comment on lines +25 to +26
const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === 'object' && value !== null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use isPlainObject from lodash instead of this helper.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isPlainObject alone is not enough because it's not a type guard, but I've updated the helper to use isPlainObject instead

* Internal unified types are registered in
* x-pack/platform/plugins/shared/cases/server/internal_attachments/index.ts
*/
describe('Unified attachment types', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding a full roundtrip for the new attachment types in an API test as well? E.g. with flag on, create a new attachment and read it back, same with flag off.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdyt if i do it in a separate PR and covers this, comment and event?

@christineweng
Copy link
Copy Markdown
Contributor Author

I wonder if we need to update getCommentContent as well now or if an empty string is good enough for lens attachments.

persistable state / lens was filtered out before this function is called

const commentsToBeUpdated = theCase.comments?.filter(
(comment) =>
// We push only user's comments
(comment.type === AttachmentType.user || comment.type === AttachmentType.actions) &&
commentsIdsToBeUpdated.has(comment.id)
);
let comments: ExternalServiceComment[] = [];
if (commentsToBeUpdated && Array.isArray(commentsToBeUpdated) && commentsToBeUpdated.length > 0) {
comments = addKibanaInformationToComments(commentsToBeUpdated, userProfiles);
}

@christineweng christineweng force-pushed the cases-migrate-persistable-1 branch from acca786 to 35a1211 Compare April 9, 2026 21:50
@janmonschke
Copy link
Copy Markdown
Contributor

persistable state / lens was filtered out before this function is called

Could you add a comment to getCommentContent that explains that we do not need to handle lens here since they're filtered out before?

@christineweng christineweng force-pushed the cases-migrate-persistable-1 branch from 35a1211 to 842d0f6 Compare April 10, 2026 16:06
Copy link
Copy Markdown
Contributor

@PhilippeOberti PhilippeOberti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for the @elastic/security-threat-hunting-investigations team

@christineweng christineweng enabled auto-merge (squash) April 13, 2026 17:39
@elasticmachine
Copy link
Copy Markdown
Contributor

elasticmachine commented Apr 13, 2026

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Defend Workflows Cypress Tests #9 / Workflow Insights (AB path) should trigger a scan with selected connector should trigger a scan with selected connector
  • [job] [logs] Defend Workflows Cypress Tests #9 / Workflow Insights (AB path) should trigger a scan with selected connector should trigger a scan with selected connector

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
cases 1992 1991 -1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
cases 2.0MB 2.0MB -52.0B
exploratoryView 138.8KB 138.7KB -86.0B
securitySolution 11.7MB 11.7MB -172.0B
total -310.0B

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
cases 167.9KB 167.9KB +56.0B

History

cc @christineweng

@christineweng christineweng merged commit 358b711 into elastic:main Apr 13, 2026
19 checks passed
tfcmarques pushed a commit to tfcmarques/kibana that referenced this pull request Apr 14, 2026
## Summary

This PR is part 1 of migrating persistable state attachment type to V2
architecture. Lens is migrated, and other persistable state attachments
(such as single metric viewer, more in [this
ticket](elastic/security-team#15569 (comment)))
should continue to behave with the feature flag off.

Feature flag: `xpack.cases.attachments.enabled: true` (restart kibana
after turning the flag on/off)

How to test: 
- Lens attachment can be added via dashboards. In Security, go to
Dashboard, Overview, click more action to add the lens chart to a case
<img width="1011" height="325" alt="image"
src="https://github.com/user-attachments/assets/fe566665-bab8-42b6-97e3-6340a90addbe"
/>

- Lens added before the change should continue to show
- Feature flag off: Lens attachment can be added and saved to
`cases-comments` SO
- Feature flag on: Lens attachment can be added and saved to
`cases-attachments` SO

Note: turning off the feature flag will exclude attachments from the
attachments SO, attachments added with flag on and disappearing when the
flag is off is expected

### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.
christineweng added a commit that referenced this pull request Apr 17, 2026
… charts (#262597)

## Summary

Dependecy: #261407 to be merged
first

This PR migrates the remaining persistable state attachments to the
unified attachment registry. Case attachment type constants are moved to
cases plugin, and a naming conversion is added to keep type names follow
the same convention.

Feature flag: xpack.cases.attachments.enabled: true (restart kibana
after turning the flag on/off)

### Key changes per plugin:

Cases: 
- Removed persistable state registry in user actions, updated related
tests
- Added schema validator on the client side

Machine learning:
- Updated persistable state registry to unified registry, updated the
shape to match the new schema
- Removed locally defined constants related to cases

AiOps:
- Updated persistable state registry to unified registry, updated the
shape to match the new schema
- Removed locally defined constants related to cases

### How to test:
Check and confirm the charts can be added and viewed in a case with the
feature flag off/on. Note that turning the flag on then off will hide
any attachments added when the flag is on, this is expected.

### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Cases Security Solution Cases team v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants