mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
[ML] Fix Trained models list crashes on browser refresh if not on page 1 (#164163)
## Summary Fixes https://github.com/elastic/kibana/issues/162618 There was an issue with setting pagination for the EUI table before models are fetched. Providing a page index while the items count is 0 caused pagination to reset with an uninitialized URL state callback. This PR adds a check to verify model list has been retrieved. Also, the Kibana `_stats` endpoint has been updated to provide a `size` parameter.
This commit is contained in:
parent
0a331f1023
commit
24baf38eaa
3 changed files with 15 additions and 7 deletions
|
@ -131,6 +131,7 @@ export const ModelsList: FC<Props> = ({
|
||||||
|
|
||||||
const { displayErrorToast } = useToastNotificationService();
|
const { displayErrorToast } = useToastNotificationService();
|
||||||
|
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [items, setItems] = useState<ModelItem[]>([]);
|
const [items, setItems] = useState<ModelItem[]>([]);
|
||||||
const [selectedModels, setSelectedModels] = useState<ModelItem[]>([]);
|
const [selectedModels, setSelectedModels] = useState<ModelItem[]>([]);
|
||||||
|
@ -183,7 +184,6 @@ export const ModelsList: FC<Props> = ({
|
||||||
try {
|
try {
|
||||||
const response = await trainedModelsApiService.getTrainedModels(undefined, {
|
const response = await trainedModelsApiService.getTrainedModels(undefined, {
|
||||||
with_pipelines: true,
|
with_pipelines: true,
|
||||||
size: 1000,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const newItems: ModelItem[] = [];
|
const newItems: ModelItem[] = [];
|
||||||
|
@ -235,6 +235,7 @@ export const ModelsList: FC<Props> = ({
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
setIsInitialized(true);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [itemIdToExpandedRowMap]);
|
}, [itemIdToExpandedRowMap]);
|
||||||
|
@ -267,7 +268,7 @@ export const ModelsList: FC<Props> = ({
|
||||||
try {
|
try {
|
||||||
if (models) {
|
if (models) {
|
||||||
const { trained_model_stats: modelsStatsResponse } =
|
const { trained_model_stats: modelsStatsResponse } =
|
||||||
await trainedModelsApiService.getTrainedModelStats(models.map((m) => m.model_id));
|
await trainedModelsApiService.getTrainedModelStats();
|
||||||
|
|
||||||
const groupByModelId = groupBy(modelsStatsResponse, 'model_id');
|
const groupByModelId = groupBy(modelsStatsResponse, 'model_id');
|
||||||
|
|
||||||
|
@ -596,6 +597,8 @@ export const ModelsList: FC<Props> = ({
|
||||||
return [...items, ...notDownloaded];
|
return [...items, ...notDownloaded];
|
||||||
}, [items]);
|
}, [items]);
|
||||||
|
|
||||||
|
if (!isInitialized) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SavedObjectsWarning onCloseFlyout={fetchModelsData} forceRefresh={isLoading} />
|
<SavedObjectsWarning onCloseFlyout={fetchModelsData} forceRefresh={isLoading} />
|
||||||
|
|
|
@ -37,6 +37,7 @@ import {
|
||||||
GetAnalyticsModelIdArg,
|
GetAnalyticsModelIdArg,
|
||||||
} from './types';
|
} from './types';
|
||||||
import type { MlClient } from '../../lib/ml_client';
|
import type { MlClient } from '../../lib/ml_client';
|
||||||
|
import { DEFAULT_TRAINED_MODELS_PAGE_SIZE } from '../../routes/trained_models';
|
||||||
|
|
||||||
export class AnalyticsManager {
|
export class AnalyticsManager {
|
||||||
private _trainedModels: estypes.MlTrainedModelConfig[] = [];
|
private _trainedModels: estypes.MlTrainedModelConfig[] = [];
|
||||||
|
@ -47,7 +48,7 @@ export class AnalyticsManager {
|
||||||
|
|
||||||
private async initData() {
|
private async initData() {
|
||||||
const [models, jobs] = await Promise.all([
|
const [models, jobs] = await Promise.all([
|
||||||
this._mlClient.getTrainedModels(),
|
this._mlClient.getTrainedModels({ size: DEFAULT_TRAINED_MODELS_PAGE_SIZE }),
|
||||||
this._mlClient.getDataFrameAnalytics({ size: 1000 }),
|
this._mlClient.getDataFrameAnalytics({ size: 1000 }),
|
||||||
]);
|
]);
|
||||||
this._trainedModels = models.trained_model_configs;
|
this._trainedModels = models.trained_model_configs;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import { ErrorType } from '@kbn/ml-error-utils';
|
import { ErrorType } from '@kbn/ml-error-utils';
|
||||||
|
import { type MlGetTrainedModelsRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||||
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
|
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
|
||||||
import { RouteInitialization } from '../types';
|
import { RouteInitialization } from '../types';
|
||||||
import { wrapError } from '../client/error_wrapper';
|
import { wrapError } from '../client/error_wrapper';
|
||||||
|
@ -29,6 +30,8 @@ import { mlLog } from '../lib/log';
|
||||||
import { forceQuerySchema } from './schemas/anomaly_detectors_schema';
|
import { forceQuerySchema } from './schemas/anomaly_detectors_schema';
|
||||||
import { modelsProvider } from '../models/model_management';
|
import { modelsProvider } from '../models/model_management';
|
||||||
|
|
||||||
|
export const DEFAULT_TRAINED_MODELS_PAGE_SIZE = 10000;
|
||||||
|
|
||||||
export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) {
|
export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) {
|
||||||
/**
|
/**
|
||||||
* @apiGroup TrainedModels
|
* @apiGroup TrainedModels
|
||||||
|
@ -60,11 +63,10 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization)
|
||||||
const { modelId } = request.params;
|
const { modelId } = request.params;
|
||||||
const { with_pipelines: withPipelines, ...query } = request.query;
|
const { with_pipelines: withPipelines, ...query } = request.query;
|
||||||
const body = await mlClient.getTrainedModels({
|
const body = await mlClient.getTrainedModels({
|
||||||
// @ts-expect-error @elastic-elasticsearch not sure why this is an error, size is a number
|
|
||||||
size: 1000,
|
|
||||||
...query,
|
...query,
|
||||||
...(modelId ? { model_id: modelId } : {}),
|
...(modelId ? { model_id: modelId } : {}),
|
||||||
});
|
size: DEFAULT_TRAINED_MODELS_PAGE_SIZE,
|
||||||
|
} as MlGetTrainedModelsRequest);
|
||||||
// model_type is missing
|
// model_type is missing
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const result = body.trained_model_configs as TrainedModelConfigResponse[];
|
const result = body.trained_model_configs as TrainedModelConfigResponse[];
|
||||||
|
@ -152,7 +154,9 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization)
|
||||||
},
|
},
|
||||||
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
|
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
|
||||||
try {
|
try {
|
||||||
const body = await mlClient.getTrainedModelsStats();
|
const body = await mlClient.getTrainedModelsStats({
|
||||||
|
size: DEFAULT_TRAINED_MODELS_PAGE_SIZE,
|
||||||
|
});
|
||||||
return response.ok({
|
return response.ok({
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue