mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Files] Add meta
prop to <FilePicker />
(#151417)
## Summary Added the `meta` prop to the `FilePicker` component, also pass this down to the `FileUpload` component so that files created via the picker can have meta set. Close https://github.com/elastic/kibana/issues/151375 ## How to test 1. Start Kibana with examples `yarn start --run-examples` 2. Go to the "Developer examples" in the side-nav menu under analytics 3. Go to "Files example" 4. Upload a file via the "Select file" button, should present an empty file picker if you have no files, otherwise use the little upload component bottom left 5. Either select files or dismiss the modal 6. Inspect the uploaded file and see the `myCool: 'meta'` entry included with other metadata ## Screenshot A file uploaded via the `FilePicker` in the "Files example" plugin. <img width="897" alt="Screenshot 2023-02-16 at 11 41 06" src="https://user-images.githubusercontent.com/8155004/219342872-c39b5d81-7421-4187-bb1c-d6815d80a3dc.png"> ### Checklist - [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
This commit is contained in:
parent
794a9493d5
commit
f1b0dd4720
9 changed files with 33 additions and 6 deletions
|
@ -174,6 +174,7 @@ export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) =
|
|||
notifications.toasts.addSuccess({
|
||||
title: 'Uploaded files',
|
||||
});
|
||||
refetch();
|
||||
}}
|
||||
onDone={(ids) => {
|
||||
notifications.toasts.addSuccess({
|
||||
|
|
|
@ -27,6 +27,7 @@ export const MyFilePicker: FunctionComponent<Props> = ({ onClose, onDone, onUplo
|
|||
onDone={(files) => onDone(files.map((f) => f.id))}
|
||||
onUpload={(n) => onUpload(n.map(({ id }) => id))}
|
||||
pageSize={50}
|
||||
uploadMeta={{ myCool: 'meta' }}
|
||||
multiple
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -20,7 +20,7 @@ interface Props {
|
|||
}
|
||||
|
||||
export const EmptyPrompt: FunctionComponent<Props> = ({ kind, multiple }) => {
|
||||
const { state } = useFilePickerContext();
|
||||
const { state, uploadMeta } = useFilePickerContext();
|
||||
const { euiTheme } = useEuiTheme();
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
|
@ -32,6 +32,7 @@ export const EmptyPrompt: FunctionComponent<Props> = ({ kind, multiple }) => {
|
|||
css={css`
|
||||
min-width: calc(${euiTheme.size.xxxl} * 6);
|
||||
`}
|
||||
meta={uploadMeta as Record<string, unknown>}
|
||||
kind={kind}
|
||||
immediate
|
||||
multiple={multiple}
|
||||
|
|
|
@ -26,7 +26,7 @@ interface Props {
|
|||
}
|
||||
|
||||
export const ModalFooter: FunctionComponent<Props> = ({ kind, onDone, onUpload, multiple }) => {
|
||||
const { state } = useFilePickerContext();
|
||||
const { state, uploadMeta } = useFilePickerContext();
|
||||
const onUploadStart = useCallback(() => state.setIsUploading(true), [state]);
|
||||
const onUploadEnd = useCallback(() => state.setIsUploading(false), [state]);
|
||||
return (
|
||||
|
@ -50,6 +50,7 @@ export const ModalFooter: FunctionComponent<Props> = ({ kind, onDone, onUpload,
|
|||
state.resetFilters();
|
||||
onUpload?.(n);
|
||||
}}
|
||||
meta={uploadMeta as Record<string, unknown>}
|
||||
onUploadStart={onUploadStart}
|
||||
onUploadEnd={onUploadEnd}
|
||||
kind={kind}
|
||||
|
|
|
@ -15,6 +15,7 @@ import { FilePickerState, createFilePickerState } from './file_picker_state';
|
|||
interface FilePickerContextValue extends FilesContextValue {
|
||||
state: FilePickerState;
|
||||
kind: string;
|
||||
uploadMeta?: unknown;
|
||||
shouldAllowDelete?: (file: FileJSON) => boolean;
|
||||
}
|
||||
|
||||
|
@ -26,6 +27,7 @@ interface FilePickerContextProps
|
|||
extends Pick<FilePickerContextValue, 'kind' | 'shouldAllowDelete'> {
|
||||
pageSize: number;
|
||||
multiple: boolean;
|
||||
uploadMeta?: unknown;
|
||||
}
|
||||
|
||||
export const FilePickerContext: FunctionComponent<FilePickerContextProps> = ({
|
||||
|
@ -34,6 +36,7 @@ export const FilePickerContext: FunctionComponent<FilePickerContextProps> = ({
|
|||
pageSize,
|
||||
multiple,
|
||||
children,
|
||||
uploadMeta,
|
||||
}) => {
|
||||
const filesContext = useFilesContext();
|
||||
const { client } = filesContext;
|
||||
|
@ -43,7 +46,7 @@ export const FilePickerContext: FunctionComponent<FilePickerContextProps> = ({
|
|||
);
|
||||
useEffect(() => state.dispose, [state]);
|
||||
return (
|
||||
<FilePickerCtx.Provider value={{ state, kind, shouldAllowDelete, ...filesContext }}>
|
||||
<FilePickerCtx.Provider value={{ state, kind, shouldAllowDelete, uploadMeta, ...filesContext }}>
|
||||
{children}
|
||||
</FilePickerCtx.Provider>
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { registerTestBed } from '@kbn/test-jest-helpers';
|
||||
|
||||
import { FileUpload } from '@kbn/shared-ux-file-upload';
|
||||
import { createMockFilesClient } from '@kbn/shared-ux-file-mocks';
|
||||
import type { FileJSON } from '@kbn/shared-ux-file-types';
|
||||
import { FilesContext } from '@kbn/shared-ux-file-context';
|
||||
|
@ -125,4 +125,18 @@ describe('FilePicker', () => {
|
|||
await actions.waitUntilLoaded();
|
||||
expect(exists(testSubjects.paginationControls)).toBe(false);
|
||||
});
|
||||
describe('passes "meta" to <FileUpload />', () => {
|
||||
it('when empty', async () => {
|
||||
// Empty state
|
||||
const { component } = await initTestBed({ uploadMeta: { foo: 'bar' } });
|
||||
expect(component.find(FileUpload).props().meta).toEqual({ foo: 'bar' });
|
||||
});
|
||||
it('when there are files', async () => {
|
||||
const { component } = await initTestBed({ uploadMeta: { bar: 'baz' } });
|
||||
client.list.mockImplementation(() =>
|
||||
Promise.resolve({ files: [{ id: 'a' }, { id: 'b' }] as FileJSON[], total: 2 })
|
||||
);
|
||||
expect(component.find(FileUpload).props().meta).toEqual({ bar: 'baz' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -55,6 +55,10 @@ export interface Props<Kind extends string = string> {
|
|||
* When a user has successfully uploaded some files this callback will be called
|
||||
*/
|
||||
onUpload?: (done: DoneNotification[]) => void;
|
||||
/**
|
||||
* `meta` value to be used for file uploads
|
||||
*/
|
||||
uploadMeta?: FileJSON['meta'];
|
||||
/**
|
||||
* The number of results to show per page.
|
||||
*/
|
||||
|
@ -151,12 +155,14 @@ export const FilePicker: FunctionComponent<Props> = ({
|
|||
kind,
|
||||
shouldAllowDelete,
|
||||
multiple = false,
|
||||
uploadMeta,
|
||||
onUpload = () => {},
|
||||
...rest
|
||||
}) => (
|
||||
<FilePickerContext
|
||||
pageSize={pageSize}
|
||||
kind={kind}
|
||||
uploadMeta={uploadMeta}
|
||||
multiple={multiple}
|
||||
shouldAllowDelete={shouldAllowDelete}
|
||||
>
|
||||
|
|
|
@ -88,7 +88,7 @@ export interface Props<Kind extends string = string> {
|
|||
onUploadStart?: () => void;
|
||||
|
||||
/**
|
||||
* Will be called when attempt ends, in error otherwise
|
||||
* Will always be called when upload ends, whether success or failure
|
||||
*/
|
||||
onUploadEnd?: () => void;
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ describe('UploadState', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('uploads all provided files and reports errors', async () => {
|
||||
it('uploads all provided files', async () => {
|
||||
testScheduler.run(({ expectObservable, cold, flush }) => {
|
||||
const file1 = { name: 'test', size: 1 } as File;
|
||||
const file2 = { name: 'test 2', size: 1 } as File;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue