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

[ResponseOps][Cases] Allow users to create templates #184104

Merged
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
37ac85f
initial commit
js-jankisalvi May 14, 2024
9be6c68
add connector field
js-jankisalvi May 16, 2024
edfc999
map connector fields
js-jankisalvi May 17, 2024
6641ec8
syncAlerts added
js-jankisalvi May 17, 2024
e1b6d3a
Merge remote-tracking branch 'upstream/feat/case_templates' into case…
js-jankisalvi May 17, 2024
6860034
Merge remote-tracking branch 'upstream/feat/case_templates' into case…
js-jankisalvi May 21, 2024
41c025d
add custom fields component
js-jankisalvi May 21, 2024
21436db
Merge remote-tracking branch 'upstream/feat/case_templates' into case…
js-jankisalvi May 23, 2024
5de5bd2
add tags field, update default value of connector
js-jankisalvi May 23, 2024
027ad22
add unit tests
js-jankisalvi May 23, 2024
e64508c
Remove custom field flyout, add tests
js-jankisalvi May 24, 2024
2024212
add template section description
js-jankisalvi May 27, 2024
81f3d0b
remove path from case fields
js-jankisalvi May 27, 2024
95d3c2f
add max length validations, tests
js-jankisalvi May 28, 2024
03d8f07
add utils, flyout and configure case tests
js-jankisalvi May 30, 2024
448ea94
add e2e test for templates
js-jankisalvi May 30, 2024
c2d1a35
Merge remote-tracking branch 'upstream/feat/case_templates' into case…
js-jankisalvi May 30, 2024
db4b1a5
Clean up
js-jankisalvi May 30, 2024
83f3a6d
set autoFocus
js-jankisalvi May 30, 2024
1999ca0
remove caseFields path
js-jankisalvi May 30, 2024
49220d9
add e2e tests to serverless
js-jankisalvi May 31, 2024
75f24e2
fix type error
js-jankisalvi May 31, 2024
82cd6af
lint fix title
js-jankisalvi May 31, 2024
a468d94
use description text area, remove session storage key for description…
js-jankisalvi May 31, 2024
ef4dc10
fix flaky functional test
js-jankisalvi Jun 3, 2024
d298b5a
add retry to wait for templates-list to exist, add optional label to …
js-jankisalvi Jun 3, 2024
9c29363
fix function name
js-jankisalvi Jun 3, 2024
a833425
Merge branch 'feat/case_templates' into case-templates-ui
kibanamachine Jun 3, 2024
4f3f91f
add custom_fields tests, remove unnecessary args from renderBody of f…
js-jankisalvi Jun 5, 2024
a28298a
Merge branch 'case-templates-ui' of https://github.com/js-jankisalvi/…
js-jankisalvi Jun 5, 2024
8379679
PR feedback 1
js-jankisalvi Jun 6, 2024
e4aa6ad
PR feedback 2
js-jankisalvi Jun 7, 2024
95a77b4
typo fixed
js-jankisalvi Jun 7, 2024
dc64cc8
test update
js-jankisalvi Jun 7, 2024
d5b7f24
Merge branch 'feat/case_templates' into case-templates-ui
js-jankisalvi Jun 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions x-pack/plugins/cases/common/types/api/configure/v1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,18 @@ describe('configure', () => {
});
});

it('does not throw when there is no description or tags', () => {
const newRequest = {
key: 'template_key_1',
name: 'Template 1',
caseFields: null,
};

expect(PathReporter.report(TemplateConfigurationRt.decode({ ...newRequest }))).toContain(
'No errors!'
);
});

it('limits name to 50 characters', () => {
const longName = 'x'.repeat(MAX_TEMPLATE_NAME_LENGTH + 1);

Expand Down
16 changes: 8 additions & 8 deletions x-pack/plugins/cases/common/types/api/configure/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,21 @@ export const TemplateConfigurationRt = rt.intersection([
* name of template
*/
name: limitedStringSchema({ fieldName: 'name', min: 1, max: MAX_TEMPLATE_NAME_LENGTH }),
/**
* description of templates
*/
description: limitedStringSchema({
fieldName: 'description',
min: 1,
max: MAX_TEMPLATE_DESCRIPTION_LENGTH,
}),
/**
* case fields
*/
caseFields: rt.union([rt.null, CaseBaseOptionalFieldsRequestRt]),
}),
rt.exact(
rt.partial({
/**
* description of templates
*/
description: limitedStringSchema({
fieldName: 'description',
min: 0,
max: MAX_TEMPLATE_DESCRIPTION_LENGTH,
}),
/**
* tags of templates
*/
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/cases/common/types/domain/case/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,4 @@ export type CaseAttributes = rt.TypeOf<typeof CaseAttributesRt>;
export type CaseSettings = rt.TypeOf<typeof CaseSettingsRt>;
export type RelatedCase = rt.TypeOf<typeof RelatedCaseRt>;
export type AttachmentTotals = rt.TypeOf<typeof AttachmentTotalsRt>;
export type CaseBaseOptionalFields = rt.TypeOf<typeof CaseBaseOptionalFieldsRt>;
2 changes: 0 additions & 2 deletions x-pack/plugins/cases/common/types/domain/configure/v1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ describe('configure', () => {
const templateWithFewCaseFields = {
key: 'template_sample_2',
name: 'Sample template 2',
description: 'this is second sample template',
tags: [],
caseFields: {
title: 'Case with sample template 2',
Expand All @@ -92,7 +91,6 @@ describe('configure', () => {
const templateWithNoCaseFields = {
key: 'template_sample_3',
name: 'Sample template 3',
description: 'this is third sample template',
caseFields: null,
};

Expand Down
8 changes: 4 additions & 4 deletions x-pack/plugins/cases/common/types/domain/configure/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,17 @@ export const TemplateConfigurationRt = rt.intersection([
* name of template
*/
name: rt.string,
/**
* description of template
*/
description: rt.string,
/**
* case fields of template
*/
caseFields: rt.union([rt.null, CaseBaseOptionalFieldsRt]),
}),
rt.exact(
rt.partial({
/**
* description of template
*/
description: rt.string,
/**
* tags of template
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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, { useMemo } from 'react';
import { sortBy } from 'lodash';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui';

import type { CasesConfigurationUI } from '../../../common/ui';
import { builderMap as customFieldsBuilderMap } from '../custom_fields/builder';
import * as i18n from './translations';

interface Props {
isLoading: boolean;
setAsOptional?: boolean;
configurationCustomFields: CasesConfigurationUI['customFields'];
}

const CustomFieldsComponent: React.FC<Props> = ({
isLoading,
setAsOptional,
configurationCustomFields,
}) => {
const sortedCustomFields = useMemo(
() => sortCustomFieldsByLabel(configurationCustomFields),
[configurationCustomFields]
);

const customFieldsComponents = sortedCustomFields.map(
(customField: CasesConfigurationUI['customFields'][number]) => {
const customFieldFactory = customFieldsBuilderMap[customField.type];
const customFieldType = customFieldFactory().build();

const CreateComponent = customFieldType.Create;

return (
<CreateComponent
isLoading={isLoading}
customFieldConfiguration={customField}
key={customField.key}
setAsOptional={setAsOptional}
/>
);
}
);

if (!configurationCustomFields.length) {
return null;
}

return (
<EuiFlexGroup direction="column" gutterSize="s">
<EuiText size="m">
<h3>{i18n.ADDITIONAL_FIELDS}</h3>
</EuiText>
<EuiSpacer size="xs" />
<EuiFlexItem data-test-subj="caseCustomFields">{customFieldsComponents}</EuiFlexItem>
</EuiFlexGroup>
);
};

CustomFieldsComponent.displayName = 'CustomFields';

export const CustomFields = React.memo(CustomFieldsComponent);

const sortCustomFieldsByLabel = (configCustomFields: CasesConfigurationUI['customFields']) => {
return sortBy(configCustomFields, (configCustomField) => {
return configCustomField.label;
});
};
Loading