Skip to content

Commit

Permalink
Refactoring frontend to not need singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathan-buttner committed Mar 31, 2023
1 parent 8f5eef1 commit 77e8680
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 79 deletions.
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(),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ 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)',
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
3 changes: 2 additions & 1 deletion x-pack/plugins/cases/common/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export interface CasesUiConfigType {
lens: boolean;
};
files: {
maxSize: number;
maxSize?: number;
allowedMimeTypes: string[];
};
}

Expand Down
13 changes: 0 additions & 13 deletions x-pack/plugins/cases/public/common/lib/kibana/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import type { CoreStart } from '@kbn/core/public';
import type { CaseFileKinds } from '../../../files/types';
import type { CasesUiConfigType } from '../../../../common/ui/types';

type GlobalServices = Pick<CoreStart, 'http'>;
Expand All @@ -15,22 +14,18 @@ export class KibanaServices {
private static kibanaVersion?: string;
private static services?: GlobalServices;
private static config?: CasesUiConfigType;
private static _fileKinds?: CaseFileKinds;

public static init({
http,
kibanaVersion,
config,
fileKinds,
}: GlobalServices & {
kibanaVersion: string;
config: CasesUiConfigType;
fileKinds: CaseFileKinds;
}) {
this.services = { http };
this.kibanaVersion = kibanaVersion;
this.config = config;
this._fileKinds = fileKinds;
}

public static get(): GlobalServices {
Expand All @@ -53,14 +48,6 @@ export class KibanaServices {
return this.config;
}

public static get fileKinds(): CaseFileKinds {
if (!this._fileKinds) {
this.throwUninitializedError();
}

return this._fileKinds;
}

private static throwUninitializedError(): never {
throw new Error(
'Kibana services not initialized - are you trying to import this module from outside of the Cases app?'
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: 12 additions & 17 deletions x-pack/plugins/cases/public/files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +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 = (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 createFileKinds = (config: FilesConfig): CaseFileKinds => {
return {
[APP_ID]: buildFileKind(config, APP_ID),
[SECURITY_SOLUTION_OWNER]: buildFileKind(config, SECURITY_SOLUTION_OWNER),
[OBSERVABILITY_OWNER]: buildFileKind(config, OBSERVABILITY_OWNER),
};
const caseFileKinds = new Map<Owner, FileKindBrowser>();

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

return caseFileKinds;
};

export const registerCaseFileKinds = (
config: FilesConfig,
filesSetupPlugin: FilesSetup
): CaseFileKinds => {
export const registerCaseFileKinds = (config: FilesConfig, filesSetupPlugin: FilesSetup) => {
const fileKinds = createFileKinds(config);

for (const fileKind of Object.values(fileKinds)) {
for (const fileKind of fileKinds.values()) {
filesSetupPlugin.registerFileKind(fileKind);
}

return fileKinds;
};
2 changes: 1 addition & 1 deletion x-pack/plugins/cases/public/files/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ import type { CasesUiConfigType } from '../containers/types';

export type FilesConfig = CasesUiConfigType['files'];

export type CaseFileKinds = Record<Owner, FileKindBrowser>;
export type CaseFileKinds = Map<Owner, FileKindBrowser>;
16 changes: 1 addition & 15 deletions x-pack/plugins/cases/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ 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 type { CaseFileKinds } from './files/types';

/**
* @public
Expand All @@ -41,10 +40,6 @@ export class CasesUiPlugin
private readonly storage = new Storage(localStorage);
private externalReferenceAttachmentTypeRegistry: ExternalReferenceAttachmentTypeRegistry;
private persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry;
// The reason this is protected is because we'll get type collisions otherwise because we're using a type guard assert
// to ensure the options member is instantiated before using it in various places
// See for more info: https://stackoverflow.com/questions/66206180/typescript-typeguard-attribut-with-method
protected fileKinds: CaseFileKinds | undefined;

constructor(private readonly initializerContext: PluginInitializerContext) {
this.kibanaVersion = initializerContext.env.packageInfo.version;
Expand All @@ -59,7 +54,7 @@ export class CasesUiPlugin
const persistableStateAttachmentTypeRegistry = this.persistableStateAttachmentTypeRegistry;

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

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

public start(core: CoreStart, plugins: CasesPluginStart): CasesUiStart {
this.ensureFieldsInitializedInSetup();

const config = this.initializerContext.config.get<CasesUiConfigType>();

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

/**
Expand Down Expand Up @@ -176,11 +168,5 @@ export class CasesUiPlugin
};
}

private ensureFieldsInitializedInSetup(): asserts this is this & { fileKinds: CaseFileKinds } {
if (this.fileKinds == null) {
throw new Error('Cases failed to initialize file kinds');
}
}

public stop() {}
}
1 change: 0 additions & 1 deletion x-pack/plugins/cases/server/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ describe('config validation', () => {
"application/x-tar",
"application/pdf",
],
"maxImageSize": 10485760,
"maxSize": 104857600,
},
"markdownPlugins": Object {
Expand Down
5 changes: 2 additions & 3 deletions x-pack/plugins/cases/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import type { TypeOf } from '@kbn/config-schema';
import { schema } from '@kbn/config-schema';
import { MAX_FILE_SIZE, MAX_IMAGE_FILE_SIZE } from '../common/constants';
import { ALLOWED_MIME_TYPES } from '../common/constants/mime_types';

export const ConfigSchema = schema.object({
Expand All @@ -18,8 +17,8 @@ export const ConfigSchema = schema.object({
allowedMimeTypes: schema.arrayOf(schema.string({ minLength: 1 }), {
defaultValue: ALLOWED_MIME_TYPES,
}),
maxSize: schema.number({ defaultValue: MAX_FILE_SIZE, min: 0 }),
maxImageSize: schema.number({ defaultValue: MAX_IMAGE_FILE_SIZE, min: 0 }),
// intentionally not setting a default here so that we can determine if the user set it
maxSize: schema.maybe(schema.number({ min: 0 })),
}),
});

Expand Down
Loading

0 comments on commit 77e8680

Please sign in to comment.