Skip to content

Commit

Permalink
Address Caue’s feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
sorenlouv committed Jul 20, 2020
1 parent a9a22f4 commit f6e3222
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 76 deletions.
27 changes: 18 additions & 9 deletions x-pack/plugins/apm/common/anomaly_detection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,36 @@ export function getSeverity(score?: number) {
}
}

// error message
export const MLErrorMessages: Record<ErrorCode, string> = {
INSUFFICIENT_LICENSE:
'You must have a platinum license to use Anomaly Detection',
INSUFFICIENT_LICENSE: i18n.translate(
'xpack.apm.anomaly_detection.error.insufficient_license',
{
defaultMessage:
'You must have a platinum license to use Anomaly Detection',
}
),
MISSING_READ_PRIVILEGES: i18n.translate(
'xpack.apm.anomaly_detection.error.insufficient_privileges',
'xpack.apm.anomaly_detection.error.missing_read_privileges',
{
defaultMessage:
'You must have "read" privileges to Machine Learning in order to view Anomaly Detection jobs',
}
),
MISSING_WRITE_PRIVILEGES: i18n.translate(
'xpack.apm.anomaly_detection.error.insufficient_privileges',
'xpack.apm.anomaly_detection.error.missing_write_privileges',
{
defaultMessage:
'You must have "write" privileges to Machine Learning and APM in order to view Anomaly Detection jobs',
}
),
ML_NOT_AVAILABLE: 'Machine learning is not available',
NOT_AVAILABLE_IN_SPACE: i18n.translate(
'xpack.apm.anomaly_detection.error.space',
ML_NOT_AVAILABLE: i18n.translate(
'xpack.apm.anomaly_detection.error.not_available',
{
defaultMessage: 'Machine learning is not available',
}
),
ML_NOT_AVAILABLE_IN_SPACE: i18n.translate(
'xpack.apm.anomaly_detection.error.not_available_in_space',
{
defaultMessage: 'Machine learning is not available in the selected space',
}
Expand All @@ -71,6 +80,6 @@ export enum ErrorCode {
MISSING_READ_PRIVILEGES = 'MISSING_READ_PRIVILEGES',
MISSING_WRITE_PRIVILEGES = 'MISSING_WRITE_PRIVILEGES',
ML_NOT_AVAILABLE = 'ML_NOT_AVAILABLE',
NOT_AVAILABLE_IN_SPACE = 'NOT_AVAILABLE_IN_SPACE',
ML_NOT_AVAILABLE_IN_SPACE = 'ML_NOT_AVAILABLE_IN_SPACE',
UNEXPECTED = 'UNEXPECTED',
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { MLErrorMessages } from '../../../../../common/anomaly_detection';
import {
MLErrorMessages,
ErrorCode,
} from '../../../../../common/anomaly_detection';
import { FETCH_STATUS } from '../../../../hooks/useFetcher';
import { ITableColumn, ManagedTable } from '../../../shared/ManagedTable';
import { LoadingStatePrompt } from '../../../shared/LoadingStatePrompt';
Expand Down Expand Up @@ -64,10 +67,6 @@ interface Props {
}
export const JobsList = ({ data, status, onAddEnvironments }: Props) => {
const { jobs, hasLegacyJobs, errorCode } = data;
const isLoading =
status === FETCH_STATUS.PENDING || status === FETCH_STATUS.LOADING;

const hasFetchFailure = status === FETCH_STATUS.FAILURE || !!errorCode;

return (
<EuiPanel>
Expand Down Expand Up @@ -116,20 +115,10 @@ export const JobsList = ({ data, status, onAddEnvironments }: Props) => {
</EuiText>
<EuiSpacer size="l" />
<ManagedTable
noItemsMessage={
// loading state
isLoading ? (
<LoadingStatePrompt />
) : // Handled error
errorCode ? (
MLErrorMessages[errorCode]
) : // Unhandled error
hasFetchFailure ? (
unhandledErrorText
) : (
emptyStateText
)
}
noItemsMessage={getNoItemsMessage({
status,
errorCode,
})}
columns={columns}
items={jobs}
/>
Expand All @@ -140,12 +129,36 @@ export const JobsList = ({ data, status, onAddEnvironments }: Props) => {
);
};

const emptyStateText = i18n.translate(
'xpack.apm.settings.anomalyDetection.jobList.emptyListText',
{ defaultMessage: 'No anomaly detection jobs.' }
);
function getNoItemsMessage({
status,
errorCode,
}: {
status: FETCH_STATUS;
errorCode?: ErrorCode;
}) {
// loading state
const isLoading =
status === FETCH_STATUS.PENDING || status === FETCH_STATUS.LOADING;
if (isLoading) {
return <LoadingStatePrompt />;
}

// A known erorr occured. Show specific error message
if (errorCode) {
return MLErrorMessages[errorCode];
}

// An unexpected error occurred. Show default error message
if (status === FETCH_STATUS.FAILURE) {
return i18n.translate(
'xpack.apm.settings.anomalyDetection.jobList.failedFetchText',
{ defaultMessage: 'Unabled to fetch anomaly detection jobs.' }
);
}

const unhandledErrorText = i18n.translate(
'xpack.apm.settings.anomalyDetection.jobList.failedFetchText',
{ defaultMessage: 'Unabled to fetch anomaly detection jobs.' }
);
// no errors occurred
return i18n.translate(
'xpack.apm.settings.anomalyDetection.jobList.emptyListText',
{ defaultMessage: 'No anomaly detection jobs.' }
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function createAnomalyDetectionJobs(

const mlCapabilities = await ml.mlSystem.mlCapabilities();
if (!mlCapabilities.mlFeatureEnabledInSpace) {
throw new AnomalyDetectionError(ErrorCode.NOT_AVAILABLE_IN_SPACE);
throw new AnomalyDetectionError(ErrorCode.ML_NOT_AVAILABLE_IN_SPACE);
}

if (!mlCapabilities.isPlatinumOrTrialLicense) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export async function getAnomalyDetectionJobs(setup: Setup, logger: Logger) {

const mlCapabilities = await ml.mlSystem.mlCapabilities();
if (!mlCapabilities.mlFeatureEnabledInSpace) {
throw new AnomalyDetectionError(ErrorCode.NOT_AVAILABLE_IN_SPACE);
throw new AnomalyDetectionError(ErrorCode.ML_NOT_AVAILABLE_IN_SPACE);
}

if (!mlCapabilities.isPlatinumOrTrialLicense) {
Expand Down
58 changes: 20 additions & 38 deletions x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ import { AnomalyDetectionError } from '../../lib/anomaly_detection/anomaly_detec

type Jobs = PromiseReturnType<typeof getAnomalyDetectionJobs>;

function getMlErrorCode(e: Error) {
// Missing privileges
if (e instanceof InsufficientMLCapabilities) {
return ErrorCode.MISSING_READ_PRIVILEGES;
}

if (e instanceof AnomalyDetectionError) {
return e.code;
}

// unexpected error
return ErrorCode.UNEXPECTED;
}

// get ML anomaly detection jobs for each environment
export const anomalyDetectionJobsRoute = createRoute(() => ({
method: 'GET',
Expand All @@ -35,30 +49,12 @@ export const anomalyDetectionJobsRoute = createRoute(() => ({
hasLegacyJobs: legacyJobs,
};
} catch (e) {
// ML error
if (e instanceof InsufficientMLCapabilities) {
return {
jobs: [] as Jobs,
hasLegacyJobs: false,
errorCode: ErrorCode.MISSING_READ_PRIVILEGES,
};
}

// AnomalyDetectionError error
if (e instanceof AnomalyDetectionError) {
return {
jobs: [] as Jobs,
hasLegacyJobs: false,
errorCode: e.code,
};
}

// unexpected error
context.logger.warn(e.message);
const mlErrorCode = getMlErrorCode(e);
context.logger.warn(`Error while retrieving ML jobs: "${e.message}"`);
return {
jobs: [] as Jobs,
hasLegacyJobs: false,
errorCode: ErrorCode.UNEXPECTED,
errorCode: mlErrorCode,
};
}
},
Expand All @@ -83,24 +79,10 @@ export const createAnomalyDetectionJobsRoute = createRoute(() => ({
try {
await createAnomalyDetectionJobs(setup, environments, context.logger);
} catch (e) {
// InsufficientMLCapabilities
if (e instanceof InsufficientMLCapabilities) {
return {
errorCode: ErrorCode.MISSING_READ_PRIVILEGES,
};
}

// AnomalyDetectionError
if (e instanceof AnomalyDetectionError) {
return {
errorCode: e.code,
};
}

// unexpected error
context.logger.warn(e.message);
const mlErrorCode = getMlErrorCode(e);
context.logger.warn(`Error while creating ML job: "${e.message}"`);
return {
errorCode: ErrorCode.UNEXPECTED,
errorCode: mlErrorCode,
};
}
},
Expand Down

0 comments on commit f6e3222

Please sign in to comment.