Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cases] Adding files configuration fields #154013

Merged
merged 12 commits into from
Apr 3, 2023
Merged
17 changes: 16 additions & 1 deletion src/plugins/files/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,25 @@

import { createMockFilesClient as createBaseMocksFilesClient } from '@kbn/shared-ux-file-mocks';
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
import type { FilesClient } from './types';
import { FilesSetup } from '.';
import type { FilesClient, FilesClientFactory } from './types';

export const createMockFilesClient = (): DeeplyMockedKeys<FilesClient> => ({
...createBaseMocksFilesClient(),
getMetrics: jest.fn(),
publicDownload: jest.fn(),
});

export const createMockFilesSetup = (): DeeplyMockedKeys<FilesSetup> => {
return {
filesClientFactory: createMockFilesClientFactory(),
registerFileKind: jest.fn(),
};
};

export const createMockFilesClientFactory = (): DeeplyMockedKeys<FilesClientFactory> => {
return {
asScoped: jest.fn(),
asUnscoped: jest.fn(),
};
};
8 changes: 7 additions & 1 deletion src/plugins/files/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { KibanaRequest } from '@kbn/core/server';
import { DeeplyMockedKeys } from '@kbn/utility-types-jest';
import * as stream from 'stream';
import { File } from '../common';
import { FileClient, FileServiceFactory, FileServiceStart } from '.';
import { FileClient, FileServiceFactory, FileServiceStart, FilesSetup } from '.';

export const createFileServiceMock = (): DeeplyMockedKeys<FileServiceStart> => ({
create: jest.fn(),
Expand Down Expand Up @@ -78,3 +78,9 @@ export const createFileClientMock = (): DeeplyMockedKeys<FileClient> => {
listShares: jest.fn().mockResolvedValue({ shares: [] }),
};
};

export const createFilesSetupMock = (): DeeplyMockedKeys<FilesSetup> => {
return {
registerFileKind: jest.fn(),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'xpack.apm.serviceMapEnabled (boolean)',
'xpack.apm.ui.enabled (boolean)',
'xpack.apm.ui.maxTraceItems (number)',
'xpack.cases.files.allowedMimeTypes (array)',
'xpack.cases.files.maxSize (number)',
'xpack.cases.markdownPlugins.lens (boolean)',
'xpack.ccr.ui.enabled (boolean)',
'xpack.cloud.base_url (string)',
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/cases/common/constants/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import type { HttpApiTagOperation, Owner } from './types';

export const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 MiB
export const MAX_IMAGE_FILE_SIZE = 10 * 1024 * 1024; // 10 MiB

export const constructFilesHttpOperationTag = (owner: Owner, operation: HttpApiTagOperation) => {
return `${owner}FilesCases${operation}`;
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/cases/common/constants/owners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const SECURITY_SOLUTION_OWNER = 'securitySolution' as const;
export const OBSERVABILITY_OWNER = 'observability' as const;
export const GENERAL_CASES_OWNER = APP_ID;

export const OWNERS = [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER, GENERAL_CASES_OWNER] as const;
export const OWNERS = [GENERAL_CASES_OWNER, OBSERVABILITY_OWNER, SECURITY_SOLUTION_OWNER] as const;

interface RouteInfo {
id: Owner;
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/cases/common/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export interface CasesUiConfigType {
markdownPlugins: {
lens: boolean;
};
files: {
maxSize?: number;
allowedMimeTypes: string[];
};
}

export const StatusAll = 'all' as const;
Expand Down
5 changes: 4 additions & 1 deletion x-pack/plugins/cases/public/common/lib/kibana/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export class KibanaServices {
http,
kibanaVersion,
config,
}: GlobalServices & { kibanaVersion: string; config: CasesUiConfigType }) {
}: GlobalServices & {
kibanaVersion: string;
config: CasesUiConfigType;
}) {
this.services = { http };
this.kibanaVersion = kibanaVersion;
this.config = config;
Expand Down
98 changes: 98 additions & 0 deletions x-pack/plugins/cases/public/files/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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 { MAX_FILE_SIZE } from '../../common/constants';
import { createMockFilesSetup } from '@kbn/files-plugin/public/mocks';
import { registerCaseFileKinds } from '.';
import type { FilesConfig } from './types';

describe('ui files index', () => {
describe('registerCaseFileKinds', () => {
const mockFilesSetup = createMockFilesSetup();

beforeEach(() => {
jest.clearAllMocks();
});

describe('allowedMimeTypes', () => {
const config: FilesConfig = {
allowedMimeTypes: ['abc'],
maxSize: undefined,
};

beforeEach(() => {
registerCaseFileKinds(config, mockFilesSetup);
});

it('sets cases allowed mime types to abc', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[0][0].allowedMimeTypes).toEqual(['abc']);
});

it('sets observability allowed mime types to abc', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[1][0].allowedMimeTypes).toEqual(['abc']);
});

it('sets securitySolution allowed mime types to 100 mb', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[2][0].allowedMimeTypes).toEqual(['abc']);
});
});

describe('max file size', () => {
describe('default max file size', () => {
const config: FilesConfig = {
allowedMimeTypes: [],
maxSize: undefined,
};

beforeEach(() => {
registerCaseFileKinds(config, mockFilesSetup);
});

it('sets cases max file size to 100 mb', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[0][0].maxSizeBytes).toEqual(
MAX_FILE_SIZE
);
});

it('sets observability max file size to 100 mb', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[1][0].maxSizeBytes).toEqual(
MAX_FILE_SIZE
);
});

it('sets securitySolution max file size to 100 mb', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[2][0].maxSizeBytes).toEqual(
MAX_FILE_SIZE
);
});
});

describe('custom file size', () => {
const config: FilesConfig = {
allowedMimeTypes: [],
maxSize: 5,
};

beforeEach(() => {
registerCaseFileKinds(config, mockFilesSetup);
});

it('sets cases max file size to 5', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[0][0].maxSizeBytes).toEqual(5);
});

it('sets observability max file size to 5', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[1][0].maxSizeBytes).toEqual(5);
});

it('sets securitySolution max file size to 5', () => {
expect(mockFilesSetup.registerFileKind.mock.calls[2][0].maxSizeBytes).toEqual(5);
});
});
});
});
});
29 changes: 17 additions & 12 deletions x-pack/plugins/cases/public/files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,35 @@

import type { FilesSetup } from '@kbn/files-plugin/public';
import type { FileKindBrowser } from '@kbn/shared-ux-file-types';
import { ALLOWED_MIME_TYPES } from '../../common/constants/mime_types';
import { constructFileKindIdByOwner, MAX_FILE_SIZE } from '../../common/constants';
import { constructFileKindIdByOwner, MAX_FILE_SIZE, OWNERS } from '../../common/constants';
import type { Owner } from '../../common/constants/types';
import { APP_ID, OBSERVABILITY_OWNER, SECURITY_SOLUTION_OWNER } from '../../common';
import type { CaseFileKinds, FilesConfig } from './types';

const buildFileKind = (owner: Owner): FileKindBrowser => {
const buildFileKind = (config: FilesConfig, owner: Owner): FileKindBrowser => {
return {
id: constructFileKindIdByOwner(owner),
allowedMimeTypes: ALLOWED_MIME_TYPES,
maxSizeBytes: MAX_FILE_SIZE,
allowedMimeTypes: config.allowedMimeTypes,
maxSizeBytes: config.maxSize ?? MAX_FILE_SIZE,
};
};

/**
* The file kind definition for interacting with the file service for the UI
*/
const CASES_FILE_KINDS: Record<Owner, FileKindBrowser> = {
[APP_ID]: buildFileKind(APP_ID),
[SECURITY_SOLUTION_OWNER]: buildFileKind(SECURITY_SOLUTION_OWNER),
[OBSERVABILITY_OWNER]: buildFileKind(OBSERVABILITY_OWNER),
const createFileKinds = (config: FilesConfig): CaseFileKinds => {
const caseFileKinds = new Map<Owner, FileKindBrowser>();

for (const owner of OWNERS) {
caseFileKinds.set(owner, buildFileKind(config, owner));
}

return caseFileKinds;
};

export const registerCaseFileKinds = (filesSetupPlugin: FilesSetup) => {
for (const fileKind of Object.values(CASES_FILE_KINDS)) {
export const registerCaseFileKinds = (config: FilesConfig, filesSetupPlugin: FilesSetup) => {
const fileKinds = createFileKinds(config);

for (const fileKind of fileKinds.values()) {
filesSetupPlugin.registerFileKind(fileKind);
}
};
14 changes: 14 additions & 0 deletions x-pack/plugins/cases/public/files/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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 { FileKindBrowser } from '@kbn/shared-ux-file-types';
import type { Owner } from '../../common/constants/types';
import type { CasesUiConfigType } from '../containers/types';

export type FilesConfig = CasesUiConfigType['files'];

export type CaseFileKinds = Map<Owner, FileKindBrowser>;
11 changes: 9 additions & 2 deletions x-pack/plugins/cases/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export class CasesUiPlugin
const externalReferenceAttachmentTypeRegistry = this.externalReferenceAttachmentTypeRegistry;
const persistableStateAttachmentTypeRegistry = this.persistableStateAttachmentTypeRegistry;

registerCaseFileKinds(plugins.files);
const config = this.initializerContext.config.get<CasesUiConfigType>();
registerCaseFileKinds(config.files, plugins.files);

if (plugins.home) {
plugins.home.featureCatalogue.register({
Expand Down Expand Up @@ -106,7 +107,13 @@ export class CasesUiPlugin

public start(core: CoreStart, plugins: CasesPluginStart): CasesUiStart {
const config = this.initializerContext.config.get<CasesUiConfigType>();
KibanaServices.init({ ...core, ...plugins, kibanaVersion: this.kibanaVersion, config });

KibanaServices.init({
...core,
...plugins,
kibanaVersion: this.kibanaVersion,
config,
});

/**
* getCasesContextLazy returns a new component each time is being called. To avoid re-renders
Expand Down
113 changes: 113 additions & 0 deletions x-pack/plugins/cases/server/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* 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 { ConfigSchema } from './config';

describe('config validation', () => {
describe('defaults', () => {
it('sets the defaults correctly', () => {
expect(ConfigSchema.validate({})).toMatchInlineSnapshot(`
Object {
"files": Object {
"allowedMimeTypes": Array [
"image/aces",
"image/apng",
"image/avci",
"image/avcs",
"image/avif",
"image/bmp",
"image/cgm",
"image/dicom-rle",
"image/dpx",
"image/emf",
"image/example",
"image/fits",
"image/g3fax",
"image/heic",
"image/heic-sequence",
"image/heif",
"image/heif-sequence",
"image/hej2k",
"image/hsj2",
"image/jls",
"image/jp2",
"image/jpeg",
"image/jph",
"image/jphc",
"image/jpm",
"image/jpx",
"image/jxr",
"image/jxrA",
"image/jxrS",
"image/jxs",
"image/jxsc",
"image/jxsi",
"image/jxss",
"image/ktx",
"image/ktx2",
"image/naplps",
"image/png",
"image/prs.btif",
"image/prs.pti",
"image/pwg-raster",
"image/svg+xml",
"image/t38",
"image/tiff",
"image/tiff-fx",
"image/vnd.adobe.photoshop",
"image/vnd.airzip.accelerator.azv",
"image/vnd.cns.inf2",
"image/vnd.dece.graphic",
"image/vnd.djvu",
"image/vnd.dwg",
"image/vnd.dxf",
"image/vnd.dvb.subtitle",
"image/vnd.fastbidsheet",
"image/vnd.fpx",
"image/vnd.fst",
"image/vnd.fujixerox.edmics-mmr",
"image/vnd.fujixerox.edmics-rlc",
"image/vnd.globalgraphics.pgb",
"image/vnd.microsoft.icon",
"image/vnd.mix",
"image/vnd.ms-modi",
"image/vnd.mozilla.apng",
"image/vnd.net-fpx",
"image/vnd.pco.b16",
"image/vnd.radiance",
"image/vnd.sealed.png",
"image/vnd.sealedmedia.softseal.gif",
"image/vnd.sealedmedia.softseal.jpg",
"image/vnd.svf",
"image/vnd.tencent.tap",
"image/vnd.valve.source.texture",
"image/vnd.wap.wbmp",
"image/vnd.xiff",
"image/vnd.zbrush.pcx",
"image/webp",
"image/wmf",
"text/plain",
"text/csv",
"text/json",
"application/json",
"application/zip",
"application/gzip",
"application/x-bzip",
"application/x-bzip2",
"application/x-7z-compressed",
"application/x-tar",
"application/pdf",
],
},
"markdownPlugins": Object {
"lens": true,
},
}
`);
});
});
});
Loading