[SECURITY_SOLUTION][ENDPOINT] Trusted apps create form UX mocks sync (#79155)

* Make flyout size `m` + condition entry value should be 100% wide
* Condition entry and group components support for small screens
* Adjust spacing below each entry in the condition group
* Move `AND` button to the condition group + style it to design mock
This commit is contained in:
Paul Tavares 2020-10-02 15:13:28 -04:00 committed by GitHub
parent 00d2105650
commit 1310ac61fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 48 deletions

View file

@ -76,7 +76,7 @@ describe('When showing the Trusted App Create Form', () => {
dataTestSub: string = dataTestSubjForForm
): HTMLButtonElement => {
return renderResult.getByTestId(
`${dataTestSub}-conditionsBuilder-AndButton`
`${dataTestSub}-conditionsBuilder-group1-AndButton`
) as HTMLButtonElement;
};
const getConditionBuilderAndConnectorBadge = (

View file

@ -130,6 +130,7 @@ export const ConditionEntry = memo<ConditionEntryProps>(
alignItems="center"
direction="row"
data-test-subj={dataTestSubj}
responsive={false}
>
<EuiFlexItem grow={2}>
<ConditionEntryCell
@ -176,6 +177,7 @@ export const ConditionEntry = memo<ConditionEntryProps>(
<EuiFieldText
name="value"
value={entry.value}
fullWidth
required
onChange={handleValueUpdate}
onBlur={handleValueOnBlur}

View file

@ -5,14 +5,39 @@
*/
import React, { memo, useCallback } from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiHideFor, EuiSpacer } from '@elastic/eui';
import styled from 'styled-components';
import { FormattedMessage } from '@kbn/i18n/react';
import { NewTrustedApp, TrustedApp } from '../../../../../../../../common/endpoint/types';
import { ConditionEntry, ConditionEntryProps } from './condition_entry';
import { AndOrBadge } from '../../../../../../../common/components/and_or_badge';
const AndBadgeFlexItem = styled(EuiFlexItem)`
padding-top: 20px;
const ConditionGroupFlexGroup = styled(EuiFlexGroup)`
// The positioning of the 'and-badge' is done by using the EuiButton's height and adding on to it
// the amount of padding used to space out each of the entries (times 2 because a spacer is also
// used above the Button), and then we adjust it with 3px
.and-badge {
padding-top: 20px;
padding-bottom: ${({ theme }) => {
return `calc(${theme.eui.euiButtonHeightSmall} + (${theme.eui.paddingSizes.s} * 2) + 3px);`;
}};
}
.group-entries {
margin-bottom: ${({ theme }) => theme.eui.paddingSizes.s};
& > * {
margin-bottom: ${({ theme }) => theme.eui.paddingSizes.s};
&:last-child {
margin-bottom: 0;
}
}
}
.and-button {
min-width: 95px;
}
`;
export interface ConditionGroupProps {
@ -20,12 +45,23 @@ export interface ConditionGroupProps {
entries: TrustedApp['entries'];
onEntryRemove: ConditionEntryProps['onRemove'];
onEntryChange: ConditionEntryProps['onChange'];
onAndClicked: () => void;
isAndDisabled?: boolean;
/** called when any of the entries is visited (triggered via `onBlur` DOM event) */
onVisited?: ConditionEntryProps['onVisited'];
'data-test-subj'?: string;
}
export const ConditionGroup = memo<ConditionGroupProps>(
({ os, entries, onEntryRemove, onEntryChange, onVisited, 'data-test-subj': dataTestSubj }) => {
({
os,
entries,
onEntryRemove,
onEntryChange,
onAndClicked,
isAndDisabled,
onVisited,
'data-test-subj': dataTestSubj,
}) => {
const getTestId = useCallback(
(suffix: string): string | undefined => {
if (dataTestSubj) {
@ -35,28 +71,53 @@ export const ConditionGroup = memo<ConditionGroupProps>(
[dataTestSubj]
);
return (
<EuiFlexGroup gutterSize="xs" data-test-subj={dataTestSubj}>
<ConditionGroupFlexGroup gutterSize="xs" data-test-subj={dataTestSubj}>
{entries.length > 1 && (
<AndBadgeFlexItem grow={false} data-test-subj={getTestId('andConnector')}>
<AndOrBadge type={'and'} includeAntennas={true} />
</AndBadgeFlexItem>
<EuiHideFor sizes={['xs', 's']}>
<EuiFlexItem
grow={false}
data-test-subj={getTestId('andConnector')}
className="and-badge"
>
<AndOrBadge type={'and'} includeAntennas={true} />
</EuiFlexItem>
</EuiHideFor>
)}
<EuiFlexItem grow={1} data-test-subj={getTestId('entries')}>
{(entries as (NewTrustedApp & { os: 'windows' })['entries']).map((entry, index) => (
<ConditionEntry
key={index}
os={os}
entry={entry}
showLabels={index === 0}
isRemoveDisabled={index === 0 && entries.length <= 1}
onRemove={onEntryRemove}
onChange={onEntryChange}
onVisited={onVisited}
data-test-subj={getTestId(`entry${index}`)}
/>
))}
<EuiFlexItem grow={1}>
<div data-test-subj={getTestId('entries')} className="group-entries">
{(entries as (NewTrustedApp & { os: 'windows' })['entries']).map((entry, index) => (
<ConditionEntry
key={index}
os={os}
entry={entry}
showLabels={index === 0}
isRemoveDisabled={index === 0 && entries.length <= 1}
onRemove={onEntryRemove}
onChange={onEntryChange}
onVisited={onVisited}
data-test-subj={getTestId(`entry${index}`)}
/>
))}
</div>
<div>
<EuiSpacer size="s" />
<EuiButton
fill
size="s"
iconType="plusInCircle"
onClick={onAndClicked}
data-test-subj={getTestId('AndButton')}
isDisabled={isAndDisabled}
className="and-button"
>
<FormattedMessage
id="xpack.securitySolution.trustedapps.logicalConditionBuilder.group.andOperator"
defaultMessage="AND"
/>
</EuiButton>
</div>
</EuiFlexItem>
</EuiFlexGroup>
</ConditionGroupFlexGroup>
);
}
);

View file

@ -5,17 +5,11 @@
*/
import React, { memo, useCallback } from 'react';
import { EuiButton, CommonProps, EuiText, EuiSpacer, EuiPanel } from '@elastic/eui';
import { CommonProps, EuiText, EuiPanel } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { ConditionGroup, ConditionGroupProps } from './components/condition_group';
const BUTTON_MIN_WIDTH = Object.freeze({ minWidth: '95px' });
export type LogicalConditionBuilderProps = CommonProps &
ConditionGroupProps & {
onAndClicked: () => void;
isAndDisabled?: boolean;
};
export type LogicalConditionBuilderProps = CommonProps & ConditionGroupProps;
export const LogicalConditionBuilder = memo<LogicalConditionBuilderProps>(
({
entries,
@ -47,26 +41,13 @@ export const LogicalConditionBuilder = memo<LogicalConditionBuilderProps>(
entries={entries}
onEntryRemove={onEntryRemove}
onEntryChange={onEntryChange}
onAndClicked={onAndClicked}
isAndDisabled={isAndDisabled}
onVisited={onVisited}
data-test-subj={getTestId('group1')}
/>
)}
</div>
<EuiSpacer size="s" />
<EuiButton
fill
size="s"
iconType="plusInCircle"
onClick={onAndClicked}
data-test-subj={getTestId('AndButton')}
isDisabled={isAndDisabled}
style={BUTTON_MIN_WIDTH}
>
<FormattedMessage
id="xpack.securitySolution.trustedapps.logicalConditionBuilder.andOperator"
defaultMessage="AND"
/>
</EuiButton>
</div>
);
}

View file

@ -84,7 +84,7 @@ export const TrustedAppsPage = memo(() => {
{location.show === 'create' && (
<CreateTrustedAppFlyout
onClose={handleAddFlyoutClose}
size="s"
size="m"
data-test-subj="addTrustedAppFlyout"
/>
)}