mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Cases] Fix bug with registered attachmets memoization (#158441)
## Summary In https://github.com/elastic/kibana/pull/156179 I fixed a bug with the memorization of the react components of registered attachments in Cases. This fix introduced another bug which I am fixing in this PR. Fixes: https://github.com/elastic/kibana/issues/158447 ### Bug782a552c
-29bd-4bae-b66b-8620cbdeb5ff ### Fixa4834ce2
-73c8-48cb-9ec4-f480133eca38 ### Checklist Delete any items that are not applicable to this PR. - [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 ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ## Release notes Fix a bug where ML embeddables, OsQuery, and IoCs attachments in a case render the wrong view.
This commit is contained in:
parent
ad85cc0727
commit
a2a0860f65
2 changed files with 170 additions and 100 deletions
|
@ -50,23 +50,27 @@ type BuilderArgs<C, R> = Pick<
|
|||
/**
|
||||
* Provides a render function for attachment type
|
||||
*/
|
||||
const getAttachmentRenderer = memoize(() => {
|
||||
let AttachmentElement: React.ReactElement;
|
||||
const getAttachmentRenderer = (cachingKey: string) =>
|
||||
memoize(
|
||||
() => {
|
||||
let AttachmentElement: React.ReactElement;
|
||||
|
||||
const renderCallback = (attachmentViewObject: AttachmentViewObject, props: object) => {
|
||||
if (!attachmentViewObject.children) return;
|
||||
const renderCallback = (attachmentViewObject: AttachmentViewObject, props: object) => {
|
||||
if (!attachmentViewObject.children) return;
|
||||
|
||||
if (!AttachmentElement) {
|
||||
AttachmentElement = React.createElement(attachmentViewObject.children, props);
|
||||
} else {
|
||||
AttachmentElement = React.cloneElement(AttachmentElement, props);
|
||||
}
|
||||
if (!AttachmentElement) {
|
||||
AttachmentElement = React.createElement(attachmentViewObject.children, props);
|
||||
} else {
|
||||
AttachmentElement = React.cloneElement(AttachmentElement, props);
|
||||
}
|
||||
|
||||
return <Suspense fallback={<EuiLoadingSpinner />}>{AttachmentElement}</Suspense>;
|
||||
};
|
||||
return <Suspense fallback={<EuiLoadingSpinner />}>{AttachmentElement}</Suspense>;
|
||||
};
|
||||
|
||||
return renderCallback;
|
||||
});
|
||||
return renderCallback;
|
||||
},
|
||||
() => cachingKey
|
||||
);
|
||||
|
||||
export const createRegisteredAttachmentUserActionBuilder = <
|
||||
C extends Comment,
|
||||
|
@ -120,7 +124,7 @@ export const createRegisteredAttachmentUserActionBuilder = <
|
|||
|
||||
const attachmentViewObject = attachmentType.getAttachmentViewObject(props);
|
||||
|
||||
const renderer = getAttachmentRenderer();
|
||||
const renderer = getAttachmentRenderer(userAction.id)();
|
||||
const actions = attachmentViewObject.getActions?.(props) ?? [];
|
||||
const [primaryActions, nonPrimaryActions] = partition(actions, 'isPrimary');
|
||||
const visiblePrimaryActions = primaryActions.slice(0, 2);
|
||||
|
|
|
@ -11,6 +11,8 @@ import {
|
|||
CommentType,
|
||||
Case,
|
||||
CommentRequest,
|
||||
CommentRequestExternalReferenceType,
|
||||
CommentRequestPersistableStateType,
|
||||
} from '@kbn/cases-plugin/common/api';
|
||||
import { expect } from 'expect';
|
||||
import {
|
||||
|
@ -85,16 +87,10 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
|
|||
describe('Attachment framework', () => {
|
||||
describe('External reference attachments', () => {
|
||||
let caseWithAttachment: Case;
|
||||
const externalReferenceAttachment = getExternalReferenceAttachment();
|
||||
|
||||
before(async () => {
|
||||
caseWithAttachment = await createAttachmentAndNavigate({
|
||||
type: CommentType.externalReference,
|
||||
externalReferenceId: 'my-id',
|
||||
externalReferenceStorage: { type: ExternalReferenceStorageType.elasticSearchDoc },
|
||||
externalReferenceAttachmentTypeId: '.test',
|
||||
externalReferenceMetadata: null,
|
||||
owner: 'cases',
|
||||
});
|
||||
caseWithAttachment = await createAttachmentAndNavigate(externalReferenceAttachment);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
@ -109,77 +105,6 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
|
|||
});
|
||||
|
||||
describe('Persistable state attachments', () => {
|
||||
const getLensState = (dataViewId: string) => ({
|
||||
title: '',
|
||||
visualizationType: 'lnsXY',
|
||||
type: 'lens',
|
||||
references: [
|
||||
{
|
||||
type: 'index-pattern',
|
||||
id: dataViewId,
|
||||
name: 'indexpattern-datasource-layer-85863a23-73a0-4e11-9774-70f77b9a5898',
|
||||
},
|
||||
],
|
||||
state: {
|
||||
visualization: {
|
||||
legend: { isVisible: true, position: 'right' },
|
||||
valueLabels: 'hide',
|
||||
fittingFunction: 'None',
|
||||
axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
labelsOrientation: { x: 0, yLeft: 0, yRight: 0 },
|
||||
gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
preferredSeriesType: 'bar_stacked',
|
||||
layers: [
|
||||
{
|
||||
layerId: '85863a23-73a0-4e11-9774-70f77b9a5898',
|
||||
accessors: ['63810bd4-8481-4aab-822a-532d8513a8b1'],
|
||||
position: 'top',
|
||||
seriesType: 'bar_stacked',
|
||||
showGridlines: false,
|
||||
layerType: 'data',
|
||||
xAccessor: 'ab807e89-c453-415b-8eb4-3986de52c923',
|
||||
},
|
||||
],
|
||||
},
|
||||
query: { query: '', language: 'kuery' },
|
||||
filters: [],
|
||||
datasourceStates: {
|
||||
formBased: {
|
||||
layers: {
|
||||
'85863a23-73a0-4e11-9774-70f77b9a5898': {
|
||||
columns: {
|
||||
'ab807e89-c453-415b-8eb4-3986de52c923': {
|
||||
label: '@timestamp',
|
||||
dataType: 'date',
|
||||
operationType: 'date_histogram',
|
||||
sourceField: '@timestamp',
|
||||
isBucketed: true,
|
||||
scale: 'interval',
|
||||
params: { interval: 'auto', includeEmptyRows: true, dropPartials: false },
|
||||
},
|
||||
'63810bd4-8481-4aab-822a-532d8513a8b1': {
|
||||
label: 'Median of id',
|
||||
dataType: 'number',
|
||||
operationType: 'median',
|
||||
sourceField: 'id',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: { emptyAsNull: true },
|
||||
},
|
||||
},
|
||||
columnOrder: [
|
||||
'ab807e89-c453-415b-8eb4-3986de52c923',
|
||||
'63810bd4-8481-4aab-822a-532d8513a8b1',
|
||||
],
|
||||
incompleteColumns: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let caseWithAttachment: Case;
|
||||
let dataViewId = '';
|
||||
|
||||
|
@ -188,12 +113,8 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
|
|||
const res = await createLogStashDataView(supertest);
|
||||
dataViewId = res.data_view.id;
|
||||
|
||||
caseWithAttachment = await createAttachmentAndNavigate({
|
||||
type: CommentType.persistableState,
|
||||
persistableStateAttachmentTypeId: '.test',
|
||||
persistableStateAttachmentState: getLensState(dataViewId),
|
||||
owner: 'cases',
|
||||
});
|
||||
const persistableStateAttachment = getPersistableStateAttachment(dataViewId);
|
||||
caseWithAttachment = await createAttachmentAndNavigate(persistableStateAttachment);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
@ -206,7 +127,65 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
|
|||
const attachmentId = caseWithAttachment?.comments?.[0].id;
|
||||
await validateAttachment(CommentType.persistableState, attachmentId);
|
||||
await retry.waitFor(
|
||||
'actions accordion to exist',
|
||||
'persistable state to exist',
|
||||
async () => await find.existsByCssSelector('.lnsExpressionRenderer')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiple attachments', () => {
|
||||
let originalCase: Case;
|
||||
let dataViewId = '';
|
||||
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional');
|
||||
const res = await createLogStashDataView(supertest);
|
||||
dataViewId = res.data_view.id;
|
||||
|
||||
originalCase = await cases.api.createCase({
|
||||
title: 'Registering multiple attachments',
|
||||
});
|
||||
|
||||
const externalReferenceAttachment = getExternalReferenceAttachment();
|
||||
const persistableStateAttachment = getPersistableStateAttachment(dataViewId);
|
||||
|
||||
await cases.api.createAttachment({
|
||||
caseId: originalCase.id,
|
||||
params: externalReferenceAttachment,
|
||||
});
|
||||
|
||||
await cases.api.createAttachment({
|
||||
caseId: originalCase.id,
|
||||
params: persistableStateAttachment,
|
||||
});
|
||||
|
||||
await cases.navigation.navigateToApp();
|
||||
await cases.casesTable.waitForCasesToBeListed();
|
||||
await cases.casesTable.goToFirstListedCase();
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await cases.api.deleteAllCases();
|
||||
await deleteLogStashDataView(supertest, dataViewId);
|
||||
await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional');
|
||||
});
|
||||
|
||||
it('renders multiple attachment types correctly', async () => {
|
||||
const theCase = await getCase({
|
||||
supertest,
|
||||
caseId: originalCase.id,
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
const externalRefAttachmentId = theCase?.comments?.[0].id;
|
||||
const persistableStateAttachmentId = theCase?.comments?.[1].id;
|
||||
await validateAttachment(CommentType.externalReference, externalRefAttachmentId);
|
||||
await validateAttachment(CommentType.persistableState, persistableStateAttachmentId);
|
||||
|
||||
await testSubjects.existOrFail('test-attachment-content');
|
||||
await retry.waitFor(
|
||||
'persistable state to exist',
|
||||
async () => await find.existsByCssSelector('.lnsExpressionRenderer')
|
||||
);
|
||||
});
|
||||
|
@ -348,3 +327,90 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
|
|||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getLensState = (dataViewId: string) => ({
|
||||
title: '',
|
||||
visualizationType: 'lnsXY',
|
||||
type: 'lens',
|
||||
references: [
|
||||
{
|
||||
type: 'index-pattern',
|
||||
id: dataViewId,
|
||||
name: 'indexpattern-datasource-layer-85863a23-73a0-4e11-9774-70f77b9a5898',
|
||||
},
|
||||
],
|
||||
state: {
|
||||
visualization: {
|
||||
legend: { isVisible: true, position: 'right' },
|
||||
valueLabels: 'hide',
|
||||
fittingFunction: 'None',
|
||||
axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
labelsOrientation: { x: 0, yLeft: 0, yRight: 0 },
|
||||
gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
preferredSeriesType: 'bar_stacked',
|
||||
layers: [
|
||||
{
|
||||
layerId: '85863a23-73a0-4e11-9774-70f77b9a5898',
|
||||
accessors: ['63810bd4-8481-4aab-822a-532d8513a8b1'],
|
||||
position: 'top',
|
||||
seriesType: 'bar_stacked',
|
||||
showGridlines: false,
|
||||
layerType: 'data',
|
||||
xAccessor: 'ab807e89-c453-415b-8eb4-3986de52c923',
|
||||
},
|
||||
],
|
||||
},
|
||||
query: { query: '', language: 'kuery' },
|
||||
filters: [],
|
||||
datasourceStates: {
|
||||
formBased: {
|
||||
layers: {
|
||||
'85863a23-73a0-4e11-9774-70f77b9a5898': {
|
||||
columns: {
|
||||
'ab807e89-c453-415b-8eb4-3986de52c923': {
|
||||
label: '@timestamp',
|
||||
dataType: 'date',
|
||||
operationType: 'date_histogram',
|
||||
sourceField: '@timestamp',
|
||||
isBucketed: true,
|
||||
scale: 'interval',
|
||||
params: { interval: 'auto', includeEmptyRows: true, dropPartials: false },
|
||||
},
|
||||
'63810bd4-8481-4aab-822a-532d8513a8b1': {
|
||||
label: 'Median of id',
|
||||
dataType: 'number',
|
||||
operationType: 'median',
|
||||
sourceField: 'id',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: { emptyAsNull: true },
|
||||
},
|
||||
},
|
||||
columnOrder: [
|
||||
'ab807e89-c453-415b-8eb4-3986de52c923',
|
||||
'63810bd4-8481-4aab-822a-532d8513a8b1',
|
||||
],
|
||||
incompleteColumns: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const getExternalReferenceAttachment = (): CommentRequestExternalReferenceType => ({
|
||||
type: CommentType.externalReference,
|
||||
externalReferenceId: 'my-id',
|
||||
externalReferenceStorage: { type: ExternalReferenceStorageType.elasticSearchDoc },
|
||||
externalReferenceAttachmentTypeId: '.test',
|
||||
externalReferenceMetadata: null,
|
||||
owner: 'cases',
|
||||
});
|
||||
|
||||
const getPersistableStateAttachment = (dataViewId: string): CommentRequestPersistableStateType => ({
|
||||
type: CommentType.persistableState,
|
||||
persistableStateAttachmentTypeId: '.test',
|
||||
persistableStateAttachmentState: getLensState(dataViewId),
|
||||
owner: 'cases',
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue