From 92232620051d6ae1b27a2f90d28782c86dac9879 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Wed, 29 Mar 2023 17:09:21 +0200 Subject: [PATCH 1/5] Created FileType for attachment registry. Registered FileType in attachment registry. Created FileDownloadButtonIcon. Created FileNameLink. Added filesContext to FilePreview. Updated file external reference metadata. Added missing translations. Added hideDefaultActions in attachment props. Created isValidFileExternalReferenceMetadata util. Added tests. --- .../cases/common/api/cases/comment/files.ts | 2 +- .../client/attachment_framework/types.ts | 5 +- .../public/components/files/add_file.test.tsx | 47 ++++---- .../public/components/files/add_file.tsx | 2 +- .../files/file_download_button_icon.test.tsx | 40 +++++++ .../files/file_download_button_icon.tsx | 41 +++++++ .../components/files/file_name_link.test.tsx | 58 ++++++++++ .../components/files/file_name_link.tsx | 40 +++++++ .../components/files/file_preview.test.tsx | 8 +- .../public/components/files/file_preview.tsx | 7 +- .../components/files/file_type.test.tsx | 107 ++++++++++++++++++ .../public/components/files/file_type.tsx | 77 +++++++++++++ .../components/files/files_table.test.tsx | 4 +- .../public/components/files/files_table.tsx | 13 +-- .../public/components/files/translations.tsx | 12 ++ .../files/use_files_table_columns.test.tsx | 1 - .../files/use_files_table_columns.tsx | 39 ++----- .../public/components/files/utils.test.tsx | 41 ++++++- .../cases/public/components/files/utils.tsx | 21 ++++ .../comment/registered_attachments.tsx | 25 ++-- .../public/internal_attachments/index.ts | 15 +++ x-pack/plugins/cases/public/plugin.ts | 2 + .../common/limiter_checker/test_utils.ts | 2 +- 23 files changed, 514 insertions(+), 95 deletions(-) create mode 100644 x-pack/plugins/cases/public/components/files/file_download_button_icon.test.tsx create mode 100644 x-pack/plugins/cases/public/components/files/file_download_button_icon.tsx create mode 100644 x-pack/plugins/cases/public/components/files/file_name_link.test.tsx create mode 100644 x-pack/plugins/cases/public/components/files/file_name_link.tsx create mode 100644 x-pack/plugins/cases/public/components/files/file_type.test.tsx create mode 100644 x-pack/plugins/cases/public/components/files/file_type.tsx create mode 100644 x-pack/plugins/cases/public/internal_attachments/index.ts diff --git a/x-pack/plugins/cases/common/api/cases/comment/files.ts b/x-pack/plugins/cases/common/api/cases/comment/files.ts index 58fee11997c74..cafa92df1b79a 100644 --- a/x-pack/plugins/cases/common/api/cases/comment/files.ts +++ b/x-pack/plugins/cases/common/api/cases/comment/files.ts @@ -13,7 +13,7 @@ export const FileAttachmentMetadataRt = rt.type({ name: rt.string, extension: rt.string, mimeType: rt.string, - createdAt: rt.string, + created: rt.string, }) ), }); diff --git a/x-pack/plugins/cases/public/client/attachment_framework/types.ts b/x-pack/plugins/cases/public/client/attachment_framework/types.ts index ea5c046a37e7c..54ede2c6da621 100644 --- a/x-pack/plugins/cases/public/client/attachment_framework/types.ts +++ b/x-pack/plugins/cases/public/client/attachment_framework/types.ts @@ -18,6 +18,7 @@ export interface AttachmentViewObject { actions?: EuiCommentProps['actions']; event?: EuiCommentProps['event']; children?: React.LazyExoticComponent>; + hideDefaultActions?: boolean; } export interface CommonAttachmentViewProps { @@ -38,7 +39,9 @@ export interface AttachmentType { id: string; icon: IconType; displayName: string; - getAttachmentViewObject: () => AttachmentViewObject; + getAttachmentViewObject: ( + props: ExternalReferenceAttachmentViewProps + ) => AttachmentViewObject; } export type ExternalReferenceAttachmentType = AttachmentType; diff --git a/x-pack/plugins/cases/public/components/files/add_file.test.tsx b/x-pack/plugins/cases/public/components/files/add_file.test.tsx index 49fcfd6a67273..1d0a8bbe98c04 100644 --- a/x-pack/plugins/cases/public/components/files/add_file.test.tsx +++ b/x-pack/plugins/cases/public/components/files/add_file.test.tsx @@ -136,31 +136,30 @@ describe('AddFile', () => { userEvent.click(await screen.findByTestId('testOnDone')); await waitFor(() => - expect(createAttachmentsMock).toBeCalledWith( - expect.objectContaining({ - caseId: 'foobar', - caseOwner: mockedTestProvidersOwner[0], - data: [ - { - externalReferenceAttachmentTypeId: '.files', - externalReferenceId: mockedExternalReferenceId, - externalReferenceMetadata: { - files: [ - { - createdAt: '2020-02-19T23:06:33.798Z', - extension: 'png', - mimeType: 'image/png', - name: 'my-super-cool-screenshot', - }, - ], - }, - externalReferenceStorage: { soType: 'file', type: 'savedObject' }, - type: 'externalReference', + expect(createAttachmentsMock).toBeCalledWith({ + caseId: 'foobar', + caseOwner: mockedTestProvidersOwner[0], + data: [ + { + externalReferenceAttachmentTypeId: '.files', + externalReferenceId: mockedExternalReferenceId, + externalReferenceMetadata: { + files: [ + { + created: '2020-02-19T23:06:33.798Z', + extension: 'png', + mimeType: 'image/png', + name: 'my-super-cool-screenshot', + }, + ], }, - ], - throwOnError: true, - }) - ) + externalReferenceStorage: { soType: 'file', type: 'savedObject' }, + type: 'externalReference', + }, + ], + throwOnError: true, + updateCase: expect.any(Function), + }) ); await waitFor(() => diff --git a/x-pack/plugins/cases/public/components/files/add_file.tsx b/x-pack/plugins/cases/public/components/files/add_file.tsx index ce2f87719cf88..f0c5636afc1ba 100644 --- a/x-pack/plugins/cases/public/components/files/add_file.tsx +++ b/x-pack/plugins/cases/public/components/files/add_file.tsx @@ -83,7 +83,7 @@ const AddFileComponent: React.FC = ({ caseId }) => { name: file.fileJSON.name, extension: file.fileJSON.extension ?? '', mimeType: file.fileJSON.mimeType ?? '', - createdAt: file.fileJSON.created, + created: file.fileJSON.created, }, ], }, diff --git a/x-pack/plugins/cases/public/components/files/file_download_button_icon.test.tsx b/x-pack/plugins/cases/public/components/files/file_download_button_icon.test.tsx new file mode 100644 index 0000000000000..3491c51656bbb --- /dev/null +++ b/x-pack/plugins/cases/public/components/files/file_download_button_icon.test.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen } from '@testing-library/react'; + +import type { AppMockRenderer } from '../../common/mock'; +import { + createAppMockRenderer, + mockedFilesClient, + mockedTestProvidersOwner, +} from '../../common/mock'; +import { FileDownloadButtonIcon } from './file_download_button_icon'; +import { basicFileMock } from '../../containers/mock'; +import { constructFileKindIdByOwner } from '../../../common/constants'; + +describe('FileDownloadButtonIcon', () => { + let appMockRender: AppMockRenderer; + + beforeEach(() => { + jest.clearAllMocks(); + appMockRender = createAppMockRenderer(); + }); + + it('renders download button with correct href', async () => { + appMockRender.render(); + + expect(await screen.findByTestId('cases-files-download-button')).toBeInTheDocument(); + + expect(mockedFilesClient.getDownloadHref).toBeCalledTimes(1); + expect(mockedFilesClient.getDownloadHref).toHaveBeenCalledWith({ + fileKind: constructFileKindIdByOwner(mockedTestProvidersOwner[0]), + id: basicFileMock.id, + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/files/file_download_button_icon.tsx b/x-pack/plugins/cases/public/components/files/file_download_button_icon.tsx new file mode 100644 index 0000000000000..d731b9a31f335 --- /dev/null +++ b/x-pack/plugins/cases/public/components/files/file_download_button_icon.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiButtonIcon } from '@elastic/eui'; +import { useFilesContext } from '@kbn/shared-ux-file-context'; + +import type { Owner } from '../../../common/constants/types'; + +import { constructFileKindIdByOwner } from '../../../common/constants'; +import { useCasesContext } from '../cases_context/use_cases_context'; +import * as i18n from './translations'; + +interface FileDownloadButtonIconProps { + fileId: string; +} + +const FileDownloadButtonIconComponent: React.FC = ({ fileId }) => { + const { owner } = useCasesContext(); + const { client: filesClient } = useFilesContext(); + + return ( + + ); +}; +FileDownloadButtonIconComponent.displayName = 'FileDownloadButtonIcon'; + +export const FileDownloadButtonIcon = React.memo(FileDownloadButtonIconComponent); diff --git a/x-pack/plugins/cases/public/components/files/file_name_link.test.tsx b/x-pack/plugins/cases/public/components/files/file_name_link.test.tsx new file mode 100644 index 0000000000000..e86d85fb02d43 --- /dev/null +++ b/x-pack/plugins/cases/public/components/files/file_name_link.test.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen, waitFor } from '@testing-library/react'; + +import type { AppMockRenderer } from '../../common/mock'; +import { createAppMockRenderer } from '../../common/mock'; +import userEvent from '@testing-library/user-event'; +import { FileNameLink } from './file_name_link'; +import { basicFileMock } from '../../containers/mock'; + +describe('FileNameLink', () => { + let appMockRender: AppMockRenderer; + + const defaultProps = { + file: basicFileMock, + showPreview: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + appMockRender = createAppMockRenderer(); + }); + + it('renders clickable name if file is image', async () => { + appMockRender.render(); + + const nameLink = await screen.findByTestId('cases-files-name-link'); + + expect(nameLink).toBeInTheDocument(); + + userEvent.click(nameLink); + + await waitFor(() => expect(defaultProps.showPreview).toHaveBeenCalled()); + }); + + it('renders simple text name if file is not image', async () => { + appMockRender.render( + + ); + + const nameLink = await screen.findByTestId('cases-files-name-text'); + + expect(nameLink).toBeInTheDocument(); + + userEvent.click(nameLink); + + await waitFor(() => expect(defaultProps.showPreview).not.toHaveBeenCalled()); + }); +}); diff --git a/x-pack/plugins/cases/public/components/files/file_name_link.tsx b/x-pack/plugins/cases/public/components/files/file_name_link.tsx new file mode 100644 index 0000000000000..9401460410a8f --- /dev/null +++ b/x-pack/plugins/cases/public/components/files/file_name_link.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiLink } from '@elastic/eui'; +import type { FileJSON } from '@kbn/shared-ux-file-types'; + +import * as i18n from './translations'; +import { isImage } from './utils'; + +interface FileNameLinkProps { + file: FileJSON; + showPreview: () => void; +} + +const FileNameLinkComponent: React.FC = ({ file, showPreview }) => { + const fileName = `${file.name}.${file.extension}`; + + if (isImage(file)) { + return ( + + {fileName} + + ); + } else { + return ( + + {fileName} + + ); + } +}; +FileNameLinkComponent.displayName = 'FileNameLink'; + +export const FileNameLink = React.memo(FileNameLinkComponent); diff --git a/x-pack/plugins/cases/public/components/files/file_preview.test.tsx b/x-pack/plugins/cases/public/components/files/file_preview.test.tsx index 48efac8aa64b5..ee70b6a517ec1 100644 --- a/x-pack/plugins/cases/public/components/files/file_preview.test.tsx +++ b/x-pack/plugins/cases/public/components/files/file_preview.test.tsx @@ -26,13 +26,7 @@ describe('FilePreview', () => { it('FilePreview rendered correctly', async () => { const mockGetDownloadRef = jest.fn(); - appMockRender.render( - - ); + appMockRender.render(); await waitFor(() => expect(mockGetDownloadRef).toBeCalledWith({ diff --git a/x-pack/plugins/cases/public/components/files/file_preview.tsx b/x-pack/plugins/cases/public/components/files/file_preview.tsx index 19429861ba389..48041bfc75649 100644 --- a/x-pack/plugins/cases/public/components/files/file_preview.tsx +++ b/x-pack/plugins/cases/public/components/files/file_preview.tsx @@ -10,6 +10,7 @@ import styled from 'styled-components'; import type { FileJSON } from '@kbn/shared-ux-file-types'; import { EuiOverlayMask, EuiFocusTrap, EuiImage } from '@elastic/eui'; +import { useFilesContext } from '@kbn/shared-ux-file-context'; import type { Owner } from '../../../common/constants/types'; @@ -18,7 +19,6 @@ import { useCasesContext } from '../cases_context/use_cases_context'; interface FilePreviewProps { closePreview: () => void; - getDownloadHref: (args: Pick, 'id' | 'fileKind'>) => string; selectedFile: FileJSON; } @@ -32,7 +32,8 @@ const StyledOverlayMask = styled(EuiOverlayMask)` } `; -export const FilePreview = ({ closePreview, selectedFile, getDownloadHref }: FilePreviewProps) => { +export const FilePreview = ({ closePreview, selectedFile }: FilePreviewProps) => { + const { client: filesClient } = useFilesContext(); const { owner } = useCasesContext(); return ( @@ -41,7 +42,7 @@ export const FilePreview = ({ closePreview, selectedFile, getDownloadHref }: Fil { + const fileType = getFileType(); + + it('invalid props return blank FileAttachmentViewObject', () => { + expect(fileType).toStrictEqual({ + id: FILE_ATTACHMENT_TYPE, + icon: 'image', + displayName: 'File Attachment Type', + getAttachmentViewObject: expect.any(Function), + }); + }); + + describe('getFileAttachmentViewObject', () => { + let appMockRender: AppMockRenderer; + + const attachmentViewProps = { + externalReferenceId: basicFileMock.id, + externalReferenceMetadata: { files: [basicFileMock] }, + caseData: { title: basicCase.title, id: basicCase.id }, + } as unknown as ExternalReferenceAttachmentViewProps; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('event renders a clickable name if the file is an image', async () => { + appMockRender = createAppMockRenderer(); + + // @ts-ignore + appMockRender.render(fileType.getAttachmentViewObject({ ...attachmentViewProps }).event); + + const nameLink = await screen.findByTestId('cases-files-name-link'); + + expect(nameLink).toBeInTheDocument(); + expect(nameLink).toHaveTextContent('my-super-cool-screenshot.png'); + }); + + it('actions renders a download button', async () => { + appMockRender = createAppMockRenderer(); + + // @ts-ignore + appMockRender.render(fileType.getAttachmentViewObject({ ...attachmentViewProps }).actions); + + expect(await screen.findByTestId('cases-files-download-button')).toBeInTheDocument(); + }); + + it('empty externalReferenceMetadata returns blank FileAttachmentViewObject', () => { + expect( + fileType.getAttachmentViewObject({ ...attachmentViewProps, externalReferenceMetadata: {} }) + ).toEqual({ + event: 'added an unknown file', + hideDefaultActions: true, + timelineAvatar: 'document', + type: 'regular', + }); + }); + + it('timelineAvatar is image if file is an image', () => { + expect(fileType.getAttachmentViewObject(attachmentViewProps)).toEqual( + expect.objectContaining({ + timelineAvatar: 'image', + }) + ); + }); + + it('timelineAvatar is document if file is not an image', () => { + expect( + fileType.getAttachmentViewObject({ + ...attachmentViewProps, + externalReferenceMetadata: { + files: [{ ...basicFileMock, mimeType: 'text/csv' } as JsonValue], + }, + }) + ).toEqual( + expect.objectContaining({ + timelineAvatar: 'document', + }) + ); + }); + + it('default actions should be hidden', () => { + expect(fileType.getAttachmentViewObject(attachmentViewProps)).toEqual( + expect.objectContaining({ + hideDefaultActions: true, + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/files/file_type.tsx b/x-pack/plugins/cases/public/components/files/file_type.tsx new file mode 100644 index 0000000000000..ac2c49a9d7b87 --- /dev/null +++ b/x-pack/plugins/cases/public/components/files/file_type.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useState } from 'react'; + +import type { FileJSON } from '@kbn/shared-ux-file-types'; + +import type { + ExternalReferenceAttachmentType, + ExternalReferenceAttachmentViewProps, +} from '../../client/attachment_framework/types'; + +import { FILE_ATTACHMENT_TYPE } from '../../../common/api'; +import { FileDownloadButtonIcon } from './file_download_button_icon'; +import { FileNameLink } from './file_name_link'; +import { FilePreview } from './file_preview'; +import * as i18n from './translations'; +import { isImage, isValidFileExternalReferenceMetadata } from './utils'; + +interface FileAttachmentEventProps { + file: FileJSON; +} + +const FileAttachmentEvent = ({ file }: FileAttachmentEventProps) => { + const [isPreviewVisible, setIsPreviewVisible] = useState(false); + + const closePreview = () => setIsPreviewVisible(false); + const showPreview = () => setIsPreviewVisible(true); + + return ( + <> + {i18n.ADDED} + + {isPreviewVisible && } + + ); +}; + +FileAttachmentEvent.displayName = 'FileAttachmentEvent'; + +const getFileAttachmentViewObject = (props: ExternalReferenceAttachmentViewProps) => { + if (!isValidFileExternalReferenceMetadata(props.externalReferenceMetadata)) { + return { + type: 'regular', + event: i18n.ADDED_UNKNOWN_FILE, + timelineAvatar: 'document', + hideDefaultActions: true, + }; + } + + const fileId = props.externalReferenceId; + + // @ts-ignore + const partialFileJSON = props.externalReferenceMetadata?.files[0] as Partial; + + const file = { + id: fileId, + ...partialFileJSON, + } as FileJSON; + + return { + event: , + timelineAvatar: isImage(file) ? 'image' : 'document', + actions: , + hideDefaultActions: true, + }; +}; + +export const getFileType = (): ExternalReferenceAttachmentType => ({ + id: FILE_ATTACHMENT_TYPE, + icon: 'image', + displayName: 'File Attachment Type', + getAttachmentViewObject: getFileAttachmentViewObject, +}); diff --git a/x-pack/plugins/cases/public/components/files/files_table.test.tsx b/x-pack/plugins/cases/public/components/files/files_table.test.tsx index 8caa94c4caa21..822a3a1402b1e 100644 --- a/x-pack/plugins/cases/public/components/files/files_table.test.tsx +++ b/x-pack/plugins/cases/public/components/files/files_table.test.tsx @@ -44,7 +44,7 @@ describe('FilesTable', () => { expect(await screen.findByTestId('cases-files-table-filename')).toBeInTheDocument(); expect(await screen.findByTestId('cases-files-table-filetype')).toBeInTheDocument(); expect(await screen.findByTestId('cases-files-table-date-added')).toBeInTheDocument(); - expect(await screen.findByTestId('cases-files-table-action-download')).toBeInTheDocument(); + expect(await screen.findByTestId('cases-files-download-button')).toBeInTheDocument(); expect(await screen.findByTestId('cases-files-table-action-delete')).toBeInTheDocument(); }); @@ -128,7 +128,7 @@ describe('FilesTable', () => { id: basicFileMock.id, }); - expect(await screen.findByTestId('cases-files-table-action-download')).toBeInTheDocument(); + expect(await screen.findByTestId('cases-files-download-button')).toBeInTheDocument(); }); it('go to next page calls onTableChange with correct values', async () => { diff --git a/x-pack/plugins/cases/public/components/files/files_table.tsx b/x-pack/plugins/cases/public/components/files/files_table.tsx index 247ca60fd3e8f..9968be7f145d2 100644 --- a/x-pack/plugins/cases/public/components/files/files_table.tsx +++ b/x-pack/plugins/cases/public/components/files/files_table.tsx @@ -10,7 +10,6 @@ import type { Pagination, EuiBasicTableProps } from '@elastic/eui'; import type { FileJSON } from '@kbn/shared-ux-file-types'; import { EuiBasicTable, EuiLoadingContent, EuiSpacer, EuiText, EuiEmptyPrompt } from '@elastic/eui'; -import { useFilesContext } from '@kbn/shared-ux-file-context'; import * as i18n from './translations'; import { useFilesTableColumns } from './use_files_table_columns'; @@ -37,7 +36,6 @@ interface FilesTableProps { } export const FilesTable = ({ caseId, items, pagination, onChange, isLoading }: FilesTableProps) => { - const { client: filesClient } = useFilesContext(); const [isPreviewVisible, setIsPreviewVisible] = useState(false); const [selectedFile, setSelectedFile] = useState(); @@ -47,10 +45,7 @@ export const FilesTable = ({ caseId, items, pagination, onChange, isLoading }: F setIsPreviewVisible(true); }; - const columns = useFilesTableColumns({ - showPreview, - getDownloadHref: filesClient.getDownloadHref, - }); + const columns = useFilesTableColumns({ showPreview }); return isLoading ? ( <> @@ -78,11 +73,7 @@ export const FilesTable = ({ caseId, items, pagination, onChange, isLoading }: F noItemsMessage={} /> {isPreviewVisible && selectedFile !== undefined && ( - + )} ); diff --git a/x-pack/plugins/cases/public/components/files/translations.tsx b/x-pack/plugins/cases/public/components/files/translations.tsx index 6ea6080d3cb33..bec9fea1447a0 100644 --- a/x-pack/plugins/cases/public/components/files/translations.tsx +++ b/x-pack/plugins/cases/public/components/files/translations.tsx @@ -78,3 +78,15 @@ export const SHOWING_FILES = (totalFiles: number) => values: { totalFiles }, defaultMessage: 'Showing {totalFiles} {totalFiles, plural, =1 {file} other {files}}', }); + +export const ADDED = i18n.translate('xpack.cases.caseView.files.added', { + defaultMessage: 'added ', +}); + +export const ADDED_UNKNOWN_FILE = i18n.translate('xpack.cases.caseView.files.addedUnknownFile', { + defaultMessage: 'added an unknown file', +}); + +export const DOWNLOAD = i18n.translate('xpack.cases.caseView.files.download', { + defaultMessage: 'download', +}); diff --git a/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx b/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx index 6ee4cbff94c6f..dab14c297b76f 100644 --- a/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx +++ b/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx @@ -16,7 +16,6 @@ describe('useCasesColumns ', () => { const useCasesColumnsProps: FilesTableColumnsProps = { showPreview: () => {}, - getDownloadHref: jest.fn(), }; beforeEach(() => { diff --git a/x-pack/plugins/cases/public/components/files/use_files_table_columns.tsx b/x-pack/plugins/cases/public/components/files/use_files_table_columns.tsx index 7477f71128162..6664dabed8ed0 100644 --- a/x-pack/plugins/cases/public/components/files/use_files_table_columns.tsx +++ b/x-pack/plugins/cases/public/components/files/use_files_table_columns.tsx @@ -10,38 +10,25 @@ import React from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; import type { FileJSON } from '@kbn/shared-ux-file-types'; -import { EuiLink, EuiButtonIcon } from '@elastic/eui'; - -import type { Owner } from '../../../common/constants/types'; - -import { constructFileKindIdByOwner } from '../../../common/constants'; -import { useCasesContext } from '../cases_context/use_cases_context'; import * as i18n from './translations'; -import { isImage, parseMimeType } from './utils'; +import { parseMimeType } from './utils'; +import { FileNameLink } from './file_name_link'; +import { FileDownloadButtonIcon } from './file_download_button_icon'; export interface FilesTableColumnsProps { showPreview: (file: FileJSON) => void; - getDownloadHref: (args: Pick, 'id' | 'fileKind'>) => string; } export const useFilesTableColumns = ({ showPreview, - getDownloadHref, }: FilesTableColumnsProps): Array> => { - const { owner } = useCasesContext(); - return [ { name: i18n.NAME, 'data-test-subj': 'cases-files-table-filename', - render: (attachment: FileJSON) => { - const fileName = `${attachment.name}.${attachment.extension}`; - if (isImage(attachment)) { - return showPreview(attachment)}>{fileName}; - } else { - return {fileName}; - } - }, + render: (file: FileJSON) => ( + showPreview(file)} /> + ), width: '60%', }, { @@ -65,19 +52,7 @@ export const useFilesTableColumns = ({ name: 'Download', isPrimary: true, description: i18n.DOWNLOAD_FILE, - render: (attachment: FileJSON) => { - return ( - - ); - }, + render: (file: FileJSON) => , }, { name: 'Delete', diff --git a/x-pack/plugins/cases/public/components/files/utils.test.tsx b/x-pack/plugins/cases/public/components/files/utils.test.tsx index c45a7b32d779c..ee21b31283f84 100644 --- a/x-pack/plugins/cases/public/components/files/utils.test.tsx +++ b/x-pack/plugins/cases/public/components/files/utils.test.tsx @@ -4,11 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { isImage, parseMimeType } from './utils'; - import type { FileJSON } from '@kbn/shared-ux-file-types'; +import type { JsonValue } from '@kbn/utility-types'; + import { imageMimeTypes, textMimeTypes } from '../../../common/constants/mime_types'; +import { basicFileMock } from '../../containers/mock'; +import { isImage, isValidFileExternalReferenceMetadata, parseMimeType } from './utils'; describe('isImage', () => { it('should return true for allowed image mime types', () => { @@ -47,3 +48,37 @@ describe('parseMimeType', () => { expect(parseMimeType('foo/bar')).toBe('Foo'); }); }); + +describe('isValidFileExternalReferenceMetadata', () => { + it('should return false for empty objects', () => { + expect(isValidFileExternalReferenceMetadata({})).toBeFalsy(); + }); + + it('should return false if the files property is missing', () => { + expect(isValidFileExternalReferenceMetadata({ foo: 'bar' })).toBeFalsy(); + }); + + it('should return false if the files property is not an array', () => { + expect(isValidFileExternalReferenceMetadata({ files: 'bar' })).toBeFalsy(); + }); + + it('should return false if file.length !== 1', () => { + expect(isValidFileExternalReferenceMetadata({ files: ['foo', 'bar'] })).toBeFalsy(); + }); + + it('should return false if files is not an array of file metadata', () => { + expect(isValidFileExternalReferenceMetadata({ files: [3] })).toBeFalsy(); + }); + + it('should return false if files is not an array of file metadata 2', () => { + expect( + isValidFileExternalReferenceMetadata({ files: [{ name: 'foo', mimeType: 'bar' }] }) + ).toBeFalsy(); + }); + + it('should return true if the metadata is as expected', () => { + expect( + isValidFileExternalReferenceMetadata({ files: [basicFileMock as unknown as JsonValue] }) + ).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/files/utils.tsx b/x-pack/plugins/cases/public/components/files/utils.tsx index dd18ee7d8e9cc..4fba6dc424618 100644 --- a/x-pack/plugins/cases/public/components/files/utils.tsx +++ b/x-pack/plugins/cases/public/components/files/utils.tsx @@ -9,6 +9,8 @@ import type { FileJSON } from '@kbn/shared-ux-file-types'; import * as i18n from './translations'; +import type { CommentRequestExternalReferenceType } from '../../../common/api'; + export const isImage = (file: FileJSON) => file.mimeType?.startsWith('image/'); export const parseMimeType = (mimeType: string | undefined) => { @@ -24,3 +26,22 @@ export const parseMimeType = (mimeType: string | undefined) => { return result[0].charAt(0).toUpperCase() + result[0].slice(1); }; + +const isFileMetadata = (file: object): boolean => { + return ( + Object.hasOwn(file, 'name') && + Object.hasOwn(file, 'mimeType') && + Object.hasOwn(file, 'extension') && + Object.hasOwn(file, 'created') + ); +}; + +export const isValidFileExternalReferenceMetadata = ( + externalReferenceMetadata: CommentRequestExternalReferenceType['externalReferenceMetadata'] +): boolean => { + return ( + Array.isArray(externalReferenceMetadata?.files) && + externalReferenceMetadata?.files?.length === 1 && + isFileMetadata(externalReferenceMetadata.files[0] as object) + ); +}; diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx index 0b314aeb0de1e..552438da3f213 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx @@ -15,7 +15,10 @@ import React, { Suspense } from 'react'; import { memoize } from 'lodash'; import { EuiCallOut, EuiCode, EuiLoadingSpinner } from '@elastic/eui'; -import type { AttachmentType } from '../../../client/attachment_framework/types'; +import type { + AttachmentType, + ExternalReferenceAttachmentViewProps, +} from '../../../client/attachment_framework/types'; import type { AttachmentTypeRegistry } from '../../../../common/registry'; import type { CommentResponse } from '../../../../common/api'; import type { UserActionBuilder, UserActionBuilderArgs } from '../types'; @@ -41,11 +44,13 @@ type BuilderArgs = Pick< * Provides a render function for attachment type */ const getAttachmentRenderer = memoize((attachmentType: AttachmentType) => { - const attachmentViewObject = attachmentType.getAttachmentViewObject(); - let AttachmentElement: React.ReactElement; const renderCallback = (props: object) => { + const attachmentViewObject = attachmentType.getAttachmentViewObject( + props as ExternalReferenceAttachmentViewProps + ); + if (!attachmentViewObject.children) return; if (!AttachmentElement) { @@ -106,11 +111,13 @@ export const createRegisteredAttachmentUserActionBuilder = < const attachmentType = registry.get(attachmentTypeId); const renderer = getAttachmentRenderer(attachmentType); - const attachmentViewObject = attachmentType.getAttachmentViewObject(); const props = { ...getAttachmentViewProps(), caseData: { id: caseData.id, title: caseData.title }, }; + const attachmentViewObject = attachmentType.getAttachmentViewObject( + props as ExternalReferenceAttachmentViewProps + ); return [ { @@ -125,10 +132,12 @@ export const createRegisteredAttachmentUserActionBuilder = < actions: ( {attachmentViewObject.actions} - handleDeleteComment(comment.id)} - /> + {!attachmentViewObject.hideDefaultActions && ( + handleDeleteComment(comment.id)} + /> + )} ), children: renderer(props), diff --git a/x-pack/plugins/cases/public/internal_attachments/index.ts b/x-pack/plugins/cases/public/internal_attachments/index.ts new file mode 100644 index 0000000000000..c8457d9a16a1b --- /dev/null +++ b/x-pack/plugins/cases/public/internal_attachments/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ExternalReferenceAttachmentTypeRegistry } from '../client/attachment_framework/external_reference_registry'; +import { getFileType } from '../components/files/file_type'; + +export const registerInternalAttachments = ( + externalRefRegistry: ExternalReferenceAttachmentTypeRegistry +) => { + externalRefRegistry.register(getFileType()); +}; diff --git a/x-pack/plugins/cases/public/plugin.ts b/x-pack/plugins/cases/public/plugin.ts index 6b828e72b279a..230a609c50f1d 100644 --- a/x-pack/plugins/cases/public/plugin.ts +++ b/x-pack/plugins/cases/public/plugin.ts @@ -28,6 +28,7 @@ import { getUICapabilities } from './client/helpers/capabilities'; import { ExternalReferenceAttachmentTypeRegistry } from './client/attachment_framework/external_reference_registry'; import { PersistableStateAttachmentTypeRegistry } from './client/attachment_framework/persistable_state_registry'; import { registerCaseFileKinds } from './files'; +import { registerInternalAttachments } from './internal_attachments'; /** * @public @@ -53,6 +54,7 @@ export class CasesUiPlugin const externalReferenceAttachmentTypeRegistry = this.externalReferenceAttachmentTypeRegistry; const persistableStateAttachmentTypeRegistry = this.persistableStateAttachmentTypeRegistry; + registerInternalAttachments(externalReferenceAttachmentTypeRegistry); registerCaseFileKinds(plugins.files); if (plugins.home) { diff --git a/x-pack/plugins/cases/server/common/limiter_checker/test_utils.ts b/x-pack/plugins/cases/server/common/limiter_checker/test_utils.ts index 6fa5e0cbbe561..1f0423dc323f5 100644 --- a/x-pack/plugins/cases/server/common/limiter_checker/test_utils.ts +++ b/x-pack/plugins/cases/server/common/limiter_checker/test_utils.ts @@ -39,7 +39,7 @@ export const createFileRequests = ({ const files: FileAttachmentMetadata['files'] = [...Array(numFiles).keys()].map((value) => { return { name: `${value}`, - createdAt: '2023-02-27T20:26:54.345Z', + created: '2023-02-27T20:26:54.345Z', extension: 'png', mimeType: 'image/png', }; From 16d8b8052e575a321fab2d25794cce6bd74464b3 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Wed, 29 Mar 2023 21:54:39 +0200 Subject: [PATCH 2/5] Fixed jest tests. Fixed typechek. Addressed PR comments. --- .../components/files/file_preview.test.tsx | 10 ++++++---- .../cases/public/components/files/utils.tsx | 19 +++++-------------- .../cases_api_integration/common/lib/mock.ts | 2 +- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/cases/public/components/files/file_preview.test.tsx b/x-pack/plugins/cases/public/components/files/file_preview.test.tsx index ee70b6a517ec1..43221f7843592 100644 --- a/x-pack/plugins/cases/public/components/files/file_preview.test.tsx +++ b/x-pack/plugins/cases/public/components/files/file_preview.test.tsx @@ -11,7 +11,11 @@ import { screen, waitFor } from '@testing-library/react'; import type { AppMockRenderer } from '../../common/mock'; import { constructFileKindIdByOwner } from '../../../common/constants'; -import { createAppMockRenderer, mockedTestProvidersOwner } from '../../common/mock'; +import { + createAppMockRenderer, + mockedTestProvidersOwner, + mockedFilesClient, +} from '../../common/mock'; import { basicFileMock } from '../../containers/mock'; import { FilePreview } from './file_preview'; @@ -24,12 +28,10 @@ describe('FilePreview', () => { }); it('FilePreview rendered correctly', async () => { - const mockGetDownloadRef = jest.fn(); - appMockRender.render(); await waitFor(() => - expect(mockGetDownloadRef).toBeCalledWith({ + expect(mockedFilesClient.getDownloadHref).toHaveBeenCalledWith({ id: basicFileMock.id, fileKind: constructFileKindIdByOwner(mockedTestProvidersOwner[0]), }) diff --git a/x-pack/plugins/cases/public/components/files/utils.tsx b/x-pack/plugins/cases/public/components/files/utils.tsx index 4fba6dc424618..8918ac0cbca1f 100644 --- a/x-pack/plugins/cases/public/components/files/utils.tsx +++ b/x-pack/plugins/cases/public/components/files/utils.tsx @@ -7,10 +7,11 @@ import type { FileJSON } from '@kbn/shared-ux-file-types'; -import * as i18n from './translations'; - import type { CommentRequestExternalReferenceType } from '../../../common/api'; +import { FileAttachmentMetadataRt } from '../../../common/api'; +import * as i18n from './translations'; + export const isImage = (file: FileJSON) => file.mimeType?.startsWith('image/'); export const parseMimeType = (mimeType: string | undefined) => { @@ -27,21 +28,11 @@ export const parseMimeType = (mimeType: string | undefined) => { return result[0].charAt(0).toUpperCase() + result[0].slice(1); }; -const isFileMetadata = (file: object): boolean => { - return ( - Object.hasOwn(file, 'name') && - Object.hasOwn(file, 'mimeType') && - Object.hasOwn(file, 'extension') && - Object.hasOwn(file, 'created') - ); -}; - export const isValidFileExternalReferenceMetadata = ( externalReferenceMetadata: CommentRequestExternalReferenceType['externalReferenceMetadata'] ): boolean => { return ( - Array.isArray(externalReferenceMetadata?.files) && - externalReferenceMetadata?.files?.length === 1 && - isFileMetadata(externalReferenceMetadata.files[0] as object) + FileAttachmentMetadataRt.is(externalReferenceMetadata) && + externalReferenceMetadata?.files?.length >= 1 ); }; diff --git a/x-pack/test/cases_api_integration/common/lib/mock.ts b/x-pack/test/cases_api_integration/common/lib/mock.ts index 149db8b0e316a..3eab32d1a26de 100644 --- a/x-pack/test/cases_api_integration/common/lib/mock.ts +++ b/x-pack/test/cases_api_integration/common/lib/mock.ts @@ -128,7 +128,7 @@ export const fileMetadata = () => ({ name: 'test_file', extension: 'png', mimeType: 'image/png', - createdAt: '2023-02-27T20:26:54.345Z', + created: '2023-02-27T20:26:54.345Z', }); export const fileAttachmentMetadata: FileAttachmentMetadata = { From 33379c99492625c5fb7cf02d33590c89f457de25 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Fri, 31 Mar 2023 14:57:19 +0200 Subject: [PATCH 3/5] Changed parameters of getAttachmentRenderer. Removed test from files utils. Created useFilePreview hook. And tests. Removed unnecessary type casts. --- .../client/attachment_framework/types.ts | 4 +- .../public/components/files/file_type.tsx | 10 ++-- .../public/components/files/files_table.tsx | 11 ++-- .../files/use_file_preview.test.tsx | 54 +++++++++++++++++++ .../components/files/use_file_preview.tsx | 17 ++++++ .../public/components/files/utils.test.tsx | 4 -- .../comment/registered_attachments.tsx | 20 ++++--- 7 files changed, 91 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx create mode 100644 x-pack/plugins/cases/public/components/files/use_file_preview.tsx diff --git a/x-pack/plugins/cases/public/client/attachment_framework/types.ts b/x-pack/plugins/cases/public/client/attachment_framework/types.ts index 54ede2c6da621..55f3a104b391e 100644 --- a/x-pack/plugins/cases/public/client/attachment_framework/types.ts +++ b/x-pack/plugins/cases/public/client/attachment_framework/types.ts @@ -39,9 +39,7 @@ export interface AttachmentType { id: string; icon: IconType; displayName: string; - getAttachmentViewObject: ( - props: ExternalReferenceAttachmentViewProps - ) => AttachmentViewObject; + getAttachmentViewObject: (props: Props) => AttachmentViewObject; } export type ExternalReferenceAttachmentType = AttachmentType; diff --git a/x-pack/plugins/cases/public/components/files/file_type.tsx b/x-pack/plugins/cases/public/components/files/file_type.tsx index ac2c49a9d7b87..b9d1f5e1342d0 100644 --- a/x-pack/plugins/cases/public/components/files/file_type.tsx +++ b/x-pack/plugins/cases/public/components/files/file_type.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useState } from 'react'; +import React from 'react'; import type { FileJSON } from '@kbn/shared-ux-file-types'; @@ -19,16 +19,14 @@ import { FileNameLink } from './file_name_link'; import { FilePreview } from './file_preview'; import * as i18n from './translations'; import { isImage, isValidFileExternalReferenceMetadata } from './utils'; +import { useFilePreview } from './use_file_preview'; interface FileAttachmentEventProps { file: FileJSON; } const FileAttachmentEvent = ({ file }: FileAttachmentEventProps) => { - const [isPreviewVisible, setIsPreviewVisible] = useState(false); - - const closePreview = () => setIsPreviewVisible(false); - const showPreview = () => setIsPreviewVisible(true); + const { isPreviewVisible, showPreview, closePreview } = useFilePreview(); return ( <> @@ -71,7 +69,7 @@ const getFileAttachmentViewObject = (props: ExternalReferenceAttachmentViewProps export const getFileType = (): ExternalReferenceAttachmentType => ({ id: FILE_ATTACHMENT_TYPE, - icon: 'image', + icon: 'document', displayName: 'File Attachment Type', getAttachmentViewObject: getFileAttachmentViewObject, }); diff --git a/x-pack/plugins/cases/public/components/files/files_table.tsx b/x-pack/plugins/cases/public/components/files/files_table.tsx index 9968be7f145d2..c8cc6320b3bbe 100644 --- a/x-pack/plugins/cases/public/components/files/files_table.tsx +++ b/x-pack/plugins/cases/public/components/files/files_table.tsx @@ -15,6 +15,7 @@ import * as i18n from './translations'; import { useFilesTableColumns } from './use_files_table_columns'; import { FilePreview } from './file_preview'; import { AddFile } from './add_file'; +import { useFilePreview } from './use_file_preview'; const EmptyFilesTable = ({ caseId }: { caseId: string }) => ( { - const [isPreviewVisible, setIsPreviewVisible] = useState(false); + const { isPreviewVisible, showPreview, closePreview } = useFilePreview(); + const [selectedFile, setSelectedFile] = useState(); - const closePreview = () => setIsPreviewVisible(false); - const showPreview = (file: FileJSON) => { + const displayPreview = (file: FileJSON) => { setSelectedFile(file); - setIsPreviewVisible(true); + showPreview(); }; - const columns = useFilesTableColumns({ showPreview }); + const columns = useFilesTableColumns({ showPreview: displayPreview }); return isLoading ? ( <> diff --git a/x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx b/x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx new file mode 100644 index 0000000000000..49e18fb818cd9 --- /dev/null +++ b/x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act, renderHook } from '@testing-library/react-hooks'; + +import { useFilePreview } from './use_file_preview'; + +describe('useFilePreview', () => { + it('isPreviewVisible is false by default', () => { + const { result } = renderHook(() => { + return useFilePreview(); + }); + + expect(result.current.isPreviewVisible).toBeFalsy(); + }); + + it('showPreview sets isPreviewVisible to true', () => { + const { result } = renderHook(() => { + return useFilePreview(); + }); + + expect(result.current.isPreviewVisible).toBeFalsy(); + + act(() => { + result.current.showPreview(); + }); + + expect(result.current.isPreviewVisible).toBeTruthy(); + }); + + it('closePreview sets isPreviewVisible to false', () => { + const { result } = renderHook(() => { + return useFilePreview(); + }); + + expect(result.current.isPreviewVisible).toBeFalsy(); + + act(() => { + result.current.showPreview(); + }); + + expect(result.current.isPreviewVisible).toBeTruthy(); + + act(() => { + result.current.closePreview(); + }); + + expect(result.current.isPreviewVisible).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/files/use_file_preview.tsx b/x-pack/plugins/cases/public/components/files/use_file_preview.tsx new file mode 100644 index 0000000000000..c802aa38fc688 --- /dev/null +++ b/x-pack/plugins/cases/public/components/files/use_file_preview.tsx @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useState } from 'react'; + +export const useFilePreview = () => { + const [isPreviewVisible, setIsPreviewVisible] = useState(false); + + const closePreview = () => setIsPreviewVisible(false); + const showPreview = () => setIsPreviewVisible(true); + + return { isPreviewVisible, showPreview, closePreview }; +}; diff --git a/x-pack/plugins/cases/public/components/files/utils.test.tsx b/x-pack/plugins/cases/public/components/files/utils.test.tsx index d3c964a78cc2d..a77d5cc39c31f 100644 --- a/x-pack/plugins/cases/public/components/files/utils.test.tsx +++ b/x-pack/plugins/cases/public/components/files/utils.test.tsx @@ -57,10 +57,6 @@ describe('isValidFileExternalReferenceMetadata', () => { expect(isValidFileExternalReferenceMetadata({ files: 'bar' })).toBeFalsy(); }); - it('should return false if file.length !== 1', () => { - expect(isValidFileExternalReferenceMetadata({ files: ['foo', 'bar'] })).toBeFalsy(); - }); - it('should return false if files is not an array of file metadata', () => { expect(isValidFileExternalReferenceMetadata({ files: [3] })).toBeFalsy(); }); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx index 552438da3f213..b6d7f11a7d385 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx @@ -15,15 +15,17 @@ import React, { Suspense } from 'react'; import { memoize } from 'lodash'; import { EuiCallOut, EuiCode, EuiLoadingSpinner } from '@elastic/eui'; + import type { AttachmentType, - ExternalReferenceAttachmentViewProps, + AttachmentViewObject, } from '../../../client/attachment_framework/types'; import type { AttachmentTypeRegistry } from '../../../../common/registry'; import type { CommentResponse } from '../../../../common/api'; import type { UserActionBuilder, UserActionBuilderArgs } from '../types'; -import { UserActionTimestamp } from '../timestamp'; import type { SnakeToCamelCase } from '../../../../common/types'; + +import { UserActionTimestamp } from '../timestamp'; import { ATTACHMENT_NOT_REGISTERED_ERROR, DEFAULT_EVENT_ATTACHMENT_TITLE } from './translations'; import { UserActionContentToolbar } from '../content_toolbar'; import { HoverableUserWithAvatarResolver } from '../../user_profiles/hoverable_user_with_avatar_resolver'; @@ -43,14 +45,10 @@ type BuilderArgs = Pick< /** * Provides a render function for attachment type */ -const getAttachmentRenderer = memoize((attachmentType: AttachmentType) => { +const getAttachmentRenderer = memoize((attachmentViewObject: AttachmentViewObject) => { let AttachmentElement: React.ReactElement; const renderCallback = (props: object) => { - const attachmentViewObject = attachmentType.getAttachmentViewObject( - props as ExternalReferenceAttachmentViewProps - ); - if (!attachmentViewObject.children) return; if (!AttachmentElement) { @@ -109,15 +107,15 @@ export const createRegisteredAttachmentUserActionBuilder = < } const attachmentType = registry.get(attachmentTypeId); - const renderer = getAttachmentRenderer(attachmentType); const props = { ...getAttachmentViewProps(), caseData: { id: caseData.id, title: caseData.title }, }; - const attachmentViewObject = attachmentType.getAttachmentViewObject( - props as ExternalReferenceAttachmentViewProps - ); + + const attachmentViewObject = attachmentType.getAttachmentViewObject(props); + + const renderer = getAttachmentRenderer(attachmentViewObject); return [ { From cb24818d7daedb379cd32bc9e9bee6795ea96c70 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Fri, 31 Mar 2023 15:27:08 +0200 Subject: [PATCH 4/5] Remove wrong usage of CASES_FILE_KINDS. --- .../plugins/cases/public/components/cases_context/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/cases/public/components/cases_context/index.tsx b/x-pack/plugins/cases/public/components/cases_context/index.tsx index 1031ec2927609..2fdfdfafefe8b 100644 --- a/x-pack/plugins/cases/public/components/cases_context/index.tsx +++ b/x-pack/plugins/cases/public/components/cases_context/index.tsx @@ -26,11 +26,11 @@ import type { ExternalReferenceAttachmentTypeRegistry } from '../../client/attac import type { PersistableStateAttachmentTypeRegistry } from '../../client/attachment_framework/persistable_state_registry'; import { CasesGlobalComponents } from './cases_global_components'; -import { DEFAULT_FEATURES } from '../../../common/constants'; +import { constructFileKindIdByOwner, DEFAULT_FEATURES } from '../../../common/constants'; import { DEFAULT_BASE_PATH } from '../../common/navigation'; import { useApplication } from './use_application'; import { casesContextReducer, getInitialCasesContextState } from './cases_context_reducer'; -import { isRegisteredOwner, CASES_FILE_KINDS } from '../../files'; +import { isRegisteredOwner } from '../../files'; export type CasesContextValueDispatch = Dispatch; @@ -132,7 +132,7 @@ export const CasesProvider: React.FC<{ value: CasesContextProps }> = ({ if (isRegisteredOwner(owner[0])) { return ( - + {contextChildren} ); From 741b91a9306559574ffec078991a42e101a2ac58 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Fri, 31 Mar 2023 22:07:38 +0200 Subject: [PATCH 5/5] Fix jest test. --- x-pack/plugins/cases/public/components/files/file_type.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/files/file_type.test.tsx b/x-pack/plugins/cases/public/components/files/file_type.test.tsx index 5b8c7e8886e24..bc8de8d43d40f 100644 --- a/x-pack/plugins/cases/public/components/files/file_type.test.tsx +++ b/x-pack/plugins/cases/public/components/files/file_type.test.tsx @@ -22,7 +22,7 @@ describe('getFileType', () => { it('invalid props return blank FileAttachmentViewObject', () => { expect(fileType).toStrictEqual({ id: FILE_ATTACHMENT_TYPE, - icon: 'image', + icon: 'document', displayName: 'File Attachment Type', getAttachmentViewObject: expect.any(Function), });