Skip to content

Commit

Permalink
address review feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
alisonelizabeth committed May 7, 2019
1 parent 4154583 commit eab7d0a
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,66 @@ import { toastNotifications } from 'ui/notify';
import {
EuiInMemoryTable,
EuiSpacer,
EuiText,
EuiTitle,
EuiButtonEmpty,
EuiToolTip,
EuiCallOut,
EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
} from '@elastic/eui';
import { loadWatchDetail, ackWatchAction } from '../../../lib/api';
import { getPageErrorCode, WatchStatus } from '../../../components';
import { PAGINATION } from '../../../../common/constants';

interface ActionError {
code: string;
message: string;
}
interface ActionStatus {
id: string;
isAckable: boolean;
state: string;
errors: ActionError[];
}

const WatchDetailUi = ({ watchId }: { watchId: string }) => {
const { error, data: watchDetail, isLoading } = loadWatchDetail(watchId);

const [actionStatuses, setActionStatuses] = useState<any[]>([]);
const [actionStatuses, setActionStatuses] = useState<ActionStatus[]>([]);
const [isActionStatusLoading, setIsActionStatusLoading] = useState<boolean>(false);

const [selectedErrorAction, setSelectedErrorAction] = useState<string | null>(null);

const actionErrors = watchDetail && watchDetail.watchErrors.actionErrors;
const hasActionErrors = actionErrors && Object.keys(actionErrors).length > 0;

useEffect(
() => {
if (watchDetail) {
setActionStatuses(watchDetail.watchStatus.actionStatuses);
const currentActionStatuses = watchDetail.watchStatus.actionStatuses;
const actionStatusesWithErrors =
currentActionStatuses &&
currentActionStatuses.map((currentActionStatus: ActionStatus) => {
return {
...currentActionStatus,
errors: actionErrors ? actionErrors[currentActionStatus.id] : [],
};
});
setActionStatuses(actionStatusesWithErrors);
}
},
[watchDetail]
);

const columns = [
const baseColumns = [
{
field: 'id',
name: i18n.translate('xpack.watcher.sections.watchDetail.watchTable.actionHeader', {
defaultMessage: 'Action',
}),
sortable: true,
truncateText: true,
render: (action: string) => {
return <EuiText>{action}</EuiText>;
},
},
{
field: 'state',
Expand All @@ -60,59 +82,92 @@ const WatchDetailUi = ({ watchId }: { watchId: string }) => {
truncateText: true,
render: (state: string) => <WatchStatus status={state} />,
},
{
actions: [
{
render: (action: any) => {
if (action.isAckable) {
return (
<EuiToolTip
content={i18n.translate(
'xpack.watcher.sections.watchDetail.watchTable.ackActionCellTooltipTitle',
{
defaultMessage: 'Acknowledge this watch action',
}
)}
>
<EuiButtonEmpty
iconType="check"
isLoading={isActionStatusLoading}
onClick={async () => {
setIsActionStatusLoading(true);
try {
const watchStatus = await ackWatchAction(watchDetail.id, action.id);
setIsActionStatusLoading(false);
return setActionStatuses(watchStatus.actionStatuses);
} catch (e) {
setIsActionStatusLoading(false);
toastNotifications.addDanger(
i18n.translate(
'xpack.watcher.sections.watchDetail.watchTable.ackActionErrorMessage',
{
defaultMessage: 'Error acknowledging action {actionId}',
values: {
actionId: action.id,
},
}
)
);
];

const errorColumn = {
field: 'errors',
name: i18n.translate('xpack.watcher.sections.watchDetail.watchTable.errorsHeader', {
defaultMessage: 'Errors',
}),
render: (errors: ActionError[], action: ActionStatus) => {
if (errors && errors.length > 0) {
return (
<EuiButtonEmpty onClick={() => setSelectedErrorAction(action.id)} color="primary">
{i18n.translate('xpack.watcher.sections.watchDetail.watchTable.errorsCellText', {
defaultMessage: '{total, number} {total, plural, one {error} other {errors}}',
values: {
total: errors.length,
},
})}
</EuiButtonEmpty>
);
}
return <Fragment />;
},
};

const actionColumn = {
actions: [
{
available: (action: ActionStatus) => action.isAckable,
render: (action: ActionStatus) => {
return (
<EuiToolTip
content={i18n.translate(
'xpack.watcher.sections.watchDetail.watchTable.ackActionCellTooltipTitle',
{
defaultMessage: 'Acknowledge this watch action',
}
)}
>
<EuiButtonEmpty
iconType="check"
isLoading={isActionStatusLoading}
onClick={async () => {
setIsActionStatusLoading(true);
try {
const watchStatus = await ackWatchAction(watchDetail.id, action.id);
const newWatchStatusesWithErrors = watchStatus.actionStatuses.map(
(newActionStatus: ActionStatus) => {
return {
...newActionStatus,
errors: actionErrors ? actionErrors[newActionStatus.id] : [],
};
}
}}
>
<FormattedMessage
id="xpack.watcher.sections.watchDetail.watchTable.ackActionCellTitle"
defaultMessage="Acknowledge"
/>
</EuiButtonEmpty>
</EuiToolTip>
);
}
return <Fragment />;
},
);
setIsActionStatusLoading(false);
return setActionStatuses(newWatchStatusesWithErrors);
} catch (e) {
setIsActionStatusLoading(false);
toastNotifications.addDanger(
i18n.translate(
'xpack.watcher.sections.watchDetail.watchTable.ackActionErrorMessage',
{
defaultMessage: 'Error acknowledging action {actionId}',
values: {
actionId: action.id,
},
}
)
);
}
}}
>
<FormattedMessage
id="xpack.watcher.sections.watchDetail.watchTable.ackActionCellTitle"
defaultMessage="Acknowledge"
/>
</EuiButtonEmpty>
</EuiToolTip>
);
},
],
},
];
},
],
};

const columns = hasActionErrors
? [...baseColumns, errorColumn, actionColumn]
: [...baseColumns, actionColumn];

// Another part of the UI will surface the error.
if (getPageErrorCode(error)) {
Expand All @@ -121,6 +176,40 @@ const WatchDetailUi = ({ watchId }: { watchId: string }) => {

return (
<Fragment>
{selectedErrorAction && (
<EuiFlyout
size="s"
aria-labelledby="flyoutActionErrorTitle"
onClose={() => setSelectedErrorAction(null)}
>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="s">
<h2 id="flyoutActionErrorTitle">{selectedErrorAction}</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiCallOut
title={i18n.translate('xpack.watcher.sections.watchDetail.actionErrorsCalloutTitle', {
defaultMessage: 'This action contains errors.',
})}
color="danger"
iconType="cross"
>
{actionErrors[selectedErrorAction].length > 1 ? (
<ul>
{actionErrors[selectedErrorAction].map(
(actionError: ActionError, errorIndex: number) => (
<li key={`action-error-${errorIndex}`}>{actionError.message}</li>
)
)}
</ul>
) : (
<p>{actionErrors[selectedErrorAction][0].message}</p>
)}
</EuiCallOut>
</EuiFlyoutBody>
</EuiFlyout>
)}
<EuiTitle size="m">
<h1>
<FormattedMessage
Expand All @@ -133,34 +222,6 @@ const WatchDetailUi = ({ watchId }: { watchId: string }) => {

<EuiSpacer size="s" />

{actionErrors && (
<EuiCallOut
title={i18n.translate('xpack.watcher.sections.watchDetail.actionErrorsCalloutTitle', {
defaultMessage: 'This watch contains action errors.',
})}
color="danger"
iconType="cross"
>
{Object.keys(actionErrors).map((action: string) => (
<Fragment key={action}>
<EuiText size="xs">
<h4>{action}</h4>
<ul>
{actionErrors[action].map(
(actionError: { message: string }, errorIndex: number) => (
<li key={`action-error-${errorIndex}`}>{actionError.message}</li>
)
)}
</ul>
</EuiText>
<EuiSpacer size="s" />
</Fragment>
))}
</EuiCallOut>
)}

<EuiSpacer size="s" />

<EuiTitle size="s">
<h2>
<FormattedMessage
Expand Down
41 changes: 2 additions & 39 deletions x-pack/plugins/watcher/server/models/action/jira_action.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,32 +99,7 @@ export class JiraAction extends BaseAction {
json.jira = {};
}

if (!json.jira.fields) {
errors.push({
code: ERROR_CODES.ERR_PROP_MISSING,
message: i18n.translate('xpack.watcher.models.jiraAction.actionJsonJiraFieldsPropertyMissingBadRequestMessage', {
defaultMessage: 'json argument must contain an {actionJsonJiraFieldsKey} property',
values: {
actionJsonJiraProjectKey: 'actionJson.jira.fields'
}
}),
});
return { errors };
}

if (!json.jira.fields.project) {
errors.push({
code: ERROR_CODES.ERR_PROP_MISSING,
message: i18n.translate('xpack.watcher.models.jiraAction.actionJsonJiraProjectPropertyMissingBadRequestMessage', {
defaultMessage: 'json argument must contain an {actionJsonJiraProject} property',
values: {
actionJsonJiraProject: 'actionJson.jira.fields.project'
}
}),
});
}

if (json.jira.fields.project && !json.jira.fields.project.key) {
if (!get(json, 'jira.fields.project.key')) {
errors.push({
code: ERROR_CODES.ERR_PROP_MISSING,
message: i18n.translate('xpack.watcher.models.jiraAction.actionJsonJiraProjectKeyPropertyMissingBadRequestMessage', {
Expand All @@ -136,19 +111,7 @@ export class JiraAction extends BaseAction {
});
}

if (!json.jira.fields.issuetype) {
errors.push({
code: ERROR_CODES.ERR_PROP_MISSING,
message: i18n.translate('xpack.watcher.models.jiraAction.actionJsonJiraIssueTypePropertyMissingBadRequestMessage', {
defaultMessage: 'json argument must contain an {actionJsonJiraIssueTypeKey} property',
values: {
actionJsonJiraIssueTypeKey: 'actionJson.jira.fields.issuetype'
}
}),
});
}

if (json.jira.fields.issuetype && !json.jira.fields.issuetype.name) {
if (!get(json, 'jira.fields.issuetype.name')) {
errors.push({
code: ERROR_CODES.ERR_PROP_MISSING,
message: i18n.translate('xpack.watcher.models.jiraAction.actionJsonJiraIssueTypePropertyMissingBadRequestMessage', {
Expand Down

0 comments on commit eab7d0a

Please sign in to comment.